Reputation: 191
The source code
#include <iostream>
#include <string>
using namespace std;
int main(){
std::string s{'a', 'b', '\0', 'c'};
std::string s1="ab\0c";
cout<<s.size()<<" "<<s<<endl;
cout<<s1.size()<<" "<<s1<<endl;
return 0;
}
and the output is
4 abc
2 ab
I wonder why this phenomenon occurs and are there any difference between these two types of initialization in C++? Thanks.
Upvotes: 5
Views: 157
Reputation: 106076
For s
you're matching the constructor that accepts an initialiser-list of characters: that's (9) in the list here. The string
class lets you construct strings from arbitrary data which may include embedded NULs, as it does in this case. The initialiser list knows its own length, so the string
captures all the characters.
For s1
, the matching constructor is (5) in the above-linked list, which accepts a const char*
- the compiler lets the array of char provided decay to such a pointer before calling that constructor, which means the constructor has no knowledge of the length of the array. Instead, it assumes you're deliberately using the ASCIIZ NUL-terminated string convention (as in "C" strings), and scans through the data to find the first NUL, considering that the terminator. Consequently, only 2 characters are captured in the string.
Note that you can explicitly capture 4 characters with...
std::string s1 { "ab\0c", 4};
...which matches constructor (4) in the list.
Rakete1111's comment below illustrates another, newer way to create such strings: auto s1 = "ab\0c"s;
.
Upvotes: 8
Reputation: 6406
The reason is that std::strings are not first class objects, they are standard library objects and have to obey the rules of C++ syntax. Unlike string literals which are first class constructs.
An std::string is allowed embedded nuls, so when it is initialised to an array, it sees the whole of the array. When it is initialised to a string literal, it sees a char *, and its only way of detecting string end is to search for the null.
Upvotes: 0