Reputation: 70267
The different construction syntaxes in C++ have always confused me a bit. In another question, it was suggested to try initializing a string like so
std::string foo{ '\0' };
This works and produces the intended result: a string of length 1 containing only the null character. In testing the code, I accidentally typed
std::string foo('\0');
This compiles fine (no warnings even with -Wall
), but terminates at runtime with
terminate called after throwing an instance of 'std::logic_error'
what(): basic_string::_M_construct null not valid
Aborted (core dumped)
Now, as far as I can tell, there is no constructor for std::string
which takes a single character as an argument, and this hypothesis is further confirmed when I attempt to pass the character indirectly.
char b = '\0';
std::string a(b);
This produces a nice, lengthy compile error. As does this
std::string a('z');
So my question is: what allows std::string a('\0');
to compile, and what makes it different from std::string a{ '\0' };
?
Footnote: Compiling using g++
on Ubuntu. This doesn't strike me as a compiler bug, but just in case...
Upvotes: 21
Views: 1195
Reputation: 1878
With C++ 14
or C++17
or C++11
, this undefined behavior results in a compile error in both clang5.0
and gcc7.2
.
#include<string>
std::string S('\0');
error: no matching function for call to 'std::__cxx11::basic_string::basic_string(char)' std::string S('\0'); ^
The UB is fixed(to give a compiler error) in recent compiler versions.
Upvotes: 0
Reputation: 15501
Character '\0'
is implicitly convertible to integer value of 0
thus representing implementation-defined null pointer constant. This:
std::string foo('\0');
calls a constructor overload accepting pointer of type const char*
as a parameter and results in undefined behavior.
It is equivalent to passing 0
or NULL
:
std::string foo(0); // UB
std::string bar(NULL); // UB
The reference for the 4th and 5th constructor overloads states:
The behavior is undefined if s... including the case when s is a null pointer.
The second statement:
std::string foo{'\0'}; // OK
calls a constructor accepting std::initializer_list<char>
as a parameter and does not cause UB.
You could call the constructor overload accepting count number of char
s instead:
std::string s(1, '\0');
Upvotes: 20