HC4*_*ica 38 c++ string foreach string-literals c++11
I have discovered a disturbing inconsistency between std::string and string literals in C++0x:
#include <iostream>
#include <string>
int main()
{
int i = 0;
for (auto e : "hello")
++i;
std::cout << "Number of elements: " << i << '\n';
i = 0;
for (auto e : std::string("hello"))
++i;
std::cout << "Number of elements: " << i << '\n';
return 0;
}
Run Code Online (Sandbox Code Playgroud)
The output is:
Number of elements: 6
Number of elements: 5
Run Code Online (Sandbox Code Playgroud)
I understand the mechanics of why this is happening: the string literal is really an array of characters that includes the null character, and when the range-based for loop calls std::end() on the character array, it gets a pointer past the end of the array; since the null character is part of the array, it thus gets a pointer past the null character.
However, I think this is very undesirable: surely std::string and string literals should behave the same when it comes to properties as basic as their length?
Is there a way to resolve this inconsistency? For example, can std::begin() and std::end() be overloaded for character arrays so that the range they delimit does not include the terminating null character? If so, why was this not done?
EDIT: To justify my indignation a bit more to those who have said that I'm just suffering the consequences of using C-style strings which are a "legacy feature", consider code like the following:
template <typename Range>
void f(Range&& r)
{
for (auto e : r)
{
...
}
}
Run Code Online (Sandbox Code Playgroud)
Would you expect f("hello") and f(std::string("hello")) to do something different?
How*_*ant 29
如果我们重载std::begin()并且std::end()const char数组返回的数据小于数组的大小,那么下面的代码将输出4而不是预期的5:
#include <iostream>
int main()
{
const char s[5] = {'h', 'e', 'l', 'l', 'o'};
int i = 0;
for (auto e : s)
++i;
std::cout << "Number of elements: " << i << '\n';
}
Run Code Online (Sandbox Code Playgroud)
Dav*_*men 21
但是,我认为这是非常不受欢迎的:当涉及到属性作为基本长度时,std :: string和字符串文字肯定应该表现相同吗?
根据定义,字符串文字在字符串的末尾有一个(隐藏的)空字符.Std :: strings没有.因为std :: strings有一个长度,所以null字符有点多余.字符串库上的标准部分显式允许非空终止字符串.
编辑
我认为在大量的投票和大量的投票中,我从未给出过更具争议性的答案.
auto应用于C样式数组时,迭代器迭代数组的每个元素.范围的确定是在编译时进行的,而不是在运行时进行的.这是不正确的,例如:
char * str;
for (auto c : str) {
do_something_with (c);
}
Run Code Online (Sandbox Code Playgroud)
有些人使用char类型的数组来保存任意数据.是的,这是一种旧式的C思维方式,也许他们应该使用C++风格的std :: array,但是这个结构非常有效且非常有用.如果他们的自动迭代器char buffer[1024];停止在元素15上,那些人会非常不高兴,因为该元素碰巧与null字符具有相同的值.一个自动迭代器Type buffer[1024];将一直运行到最后.什么使char数组如此值得完全不同的实现?
请注意,如果您希望字符数组上的自动迭代器提前停止,则可以使用一种简单的机制:if (c == '0') break;向循环体添加语句.
底线:这里没有矛盾.在auto超过一个char []数组迭代器是自动的迭代器是如何工作的任何其他C数组一致.
Lig*_*ica 19
你6在第一种情况下得到的是一个抽象泄漏,在C语言中无法避免.std::string"修复"了.为了兼容性,C风格的字符串文字的行为在C++中不会改变.
例如,std :: begin()和std :: end()是否可以为字符数组重载,以便它们分隔的范围不包括终止空字符?如果是这样,为什么没有这样做?
假设通过指针(相对于char[N])进行访问,只需在包含字符数的字符串中嵌入变量,这样NULL就不再需要搜索了.哎呀!那是std::string.
"解决不一致"的方法不是使用遗留功能.
根据N3290 6.5.4,如果范围是一个数组,边界值会自动初始化而不需要begin/ endfunction dispatch.
那么,如何准备如下的包装?
struct literal_t {
char const *b, *e;
literal_t( char const* b, char const* e ) : b( b ), e( e ) {}
char const* begin() const { return b; }
char const* end () const { return e; }
};
template< int N >
literal_t literal( char const (&a)[N] ) {
return literal_t( a, a + N - 1 );
};
Run Code Online (Sandbox Code Playgroud)
那么以下代码将是有效的:
for (auto e : literal("hello")) ...
Run Code Online (Sandbox Code Playgroud)
如果您的编译器提供用户定义的文字,则缩写可能有所帮助:
literal operator"" _l( char const* p, std::size_t l ) {
return literal_t( p, p + l ); // l excludes '\0'
}
for (auto e : "hello"_l) ...
Run Code Online (Sandbox Code Playgroud)
编辑:以下将有较小的开销(虽然用户定义的文字将不可用).
template< size_t N >
char const (&literal( char const (&x)[ N ] ))[ N - 1 ] {
return (char const(&)[ N - 1 ]) x;
}
for (auto e : literal("hello")) ...
Run Code Online (Sandbox Code Playgroud)
可以使用 C++0x 工具箱中的另一个工具来解决不一致问题:用户定义的文字。使用适当定义的用户定义文字:
std::string operator""s(const char* p, size_t n)
{
return string(p, n);
}
Run Code Online (Sandbox Code Playgroud)
我们将能够写:
int i = 0;
for (auto e : "hello"s)
++i;
std::cout << "Number of elements: " << i << '\n';
Run Code Online (Sandbox Code Playgroud)
现在输出预期的数字:
Number of elements: 5
Run Code Online (Sandbox Code Playgroud)
有了这些新的 std::string 文字,可以说再也没有理由使用 C 风格的字符串文字了。
| 归档时间: |
|
| 查看次数: |
3107 次 |
| 最近记录: |