Как `const std :: string & s = nullptr` работает как необязательный параметр - PullRequest
5 голосов
/ 06 мая 2019

Насколько мне известно, ссылка не может быть нулевой, но когда я запускаю такой код:

#include <iostream>
#include <string>

void test(int i, const std::string& s = nullptr) {
  std::cout << i << " " << s << std::endl;
}

int main() {
  test(1, "test");
  test(2);
}

необязательный параметр s может быть нулевым, и код создается. Более того, при запуске test(2) программа выдает исключения, а не печатает случайные строки.

Когда я изменил s на какой-то базовый тип, такой как int, он не смог скомпилироваться, поэтому я думаю, что магия остается внутри класса string, но как?

И более того, как я могу проверить, является ли s нулевым или нет? если я использую if(s==nullptr) или if(s.empty()), он не скомпилируется.

Ответы [ 2 ]

11 голосов
/ 06 мая 2019

test инициализировал свой аргумент с помощью конструктора число 5 из std::basic_string<char>:

basic_string( const CharT* s,
              const Allocator& alloc = Allocator() );

Так как он должен материализовать временную (std::string) привязку к этой ссылке. Это связано с тем, что ссылка должна быть привязана к объекту правильного типа, а std::nullptr_t - нет. И указанный конструктор имеет ограничение not null на передаваемый указатель. Вызов test без явного аргумента приводит к неопределенному поведению.

Чтобы быть совершенно ясным, в правильно сформированной программе на C ++ нет такого понятия, как нулевая ссылка. Ссылка должна быть привязана к действительному объекту . Попытка инициализировать его с помощью nullptr приведет только к конвертации.

Поскольку std::string является объектом с четко определенным «пустым» состоянием, фиксированная версия может просто передать инициализированную строку по умолчанию:

void test(int i, const std::string& s = {}); // Empty string by default.

После устранения нарушения договора s.empty() должен снова дать значимые результаты.

4 голосов
/ 06 мая 2019

Ссылка действительно не может быть нулевой, однако const std::string& s = nulltr не делает то, что вы думаете, она делает. Если второй параметр не указан, компилятор создаст строковый объект, вызывающий implicit строковый конструктор, который принимает указатель на завершающуюся нулем строку в качестве первого параметра. Итак, test(2); вызов выглядит так:

test(2, ::std::string(static_cast<char const *>(nullptr), ::std::string::allocator_type()));

Обратите внимание, что передача nullptr в качестве этого первого параметра вызывает неопределенное поведение.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...