Разница между методами построения объектов С++
Различные синтаксисы конструкции в С++ всегда меня путают. В еще один вопрос было предложено попробовать инициализировать строку так:
std::string foo{ '\0' };
Это работает и создает предполагаемый результат: строка длиной 1, содержащая только нулевой символ. При тестировании кода я случайно набрал
std::string foo('\0');
Это компилируется отлично (без предупреждений даже с -Wall
), но завершается во время выполнения с помощью
terminate called after throwing an instance of 'std::logic_error'
what(): basic_string::_M_construct null not valid
Aborted (core dumped)
Теперь, насколько я могу судить, нет конструктора для std::string
, который принимает один символ в качестве аргумента, и это гипотеза подтверждается, когда я пытаюсь передать персонажа косвенно.
char b = '\0';
std::string a(b);
Это создает хорошую, длинную ошибку компиляции. Как это делает
std::string a('z');
Итак, мой вопрос: что позволяет std::string a('\0');
компилировать, а что отличает его от std::string a{ '\0' };
?
Сноска: компиляция с использованием g++
в Ubuntu. Это не ударит меня как ошибка компилятора, но на всякий случай...
Ответы
Ответ 1
Символ '\0'
неявно конвертируется в целочисленное значение 0
, представляя, таким образом, константу указателя, определяемую реализацией. Это:
std::string foo('\0');
вызывает перегрузку конструктора, принимающую указатель типа const char*
в качестве параметра и приводит к поведению undefined.
Это эквивалентно прохождению 0
или NULL
:
std::string foo(0); // UB
std::string bar(NULL); // UB
reference для 4-го и 5-го конструкторов перегружает состояния:
Поведение undefined, если s... включая случай, когда s является null указатель.
Второе утверждение:
std::string foo{'\0'}; // OK
вызывает конструктор, принимающий std::initializer_list<char>
в качестве параметра и не вызывающий UB.
Вы можете вызвать перегрузку конструктора, принимающую число счетчика char
вместо:
std::string s(1, '\0');
Ответ 2
С C++ 14
или C++17
или C++11
, это поведение undefined приводит к ошибке компиляции как в clang5.0
, так и gcc7.2
.
#include<string>
std::string S('\0');
ошибка: нет соответствующей функции для вызова 'std:: __ cxx11:: basic_string:: basic_string (char)' std::stringS ( '\ 0'); ^
UB фиксирован (чтобы дать ошибку компилятора) в последних версиях компилятора.