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; }
The output is:
Number of elements: 6 Number of elements: 5
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) { ... } }
Would you expect f("hello")
and f(std::string("hello"))
to do something different?
There is no functionality difference between string and std::string because they're the same type.
C-strings are simply implemented as a char array which is terminated by a null character (aka 0 ). This last part of the definition is important: all C-strings are char arrays, but not all char arrays are c-strings. C-strings of this form are called “string literals“: const char * str = "This is a string literal.
A String Literal, also known as a string constant or constant string, is a string of characters enclosed in double quotes, such as "To err is human - To really foul things up requires a computer." String literals are stored in C as an array of chars, terminted by a null byte.
std::string literals (C++14)This kind of string literal produces a temporary object of type std::string , std::wstring , std::u32string , or std::u16string , depending on the prefix that is specified.
If we overloaded std::begin()
and std::end()
for const char arrays to return one less than the size of the array, then the following code would output 4 instead of the expected 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'; }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With