Подтвердить что ты не робот

Разница между методами построения объектов С++

Различные синтаксисы конструкции в С++ всегда меня путают. В еще один вопрос было предложено попробовать инициализировать строку так:

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. Это не ударит меня как ошибка компилятора, но на всякий случай...

4b9b3361

Ответ 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 фиксирован (чтобы дать ошибку компилятора) в последних версиях компилятора.