Является ли nullptr ложным?

При использовании в качестве логического выражения или преобразовании в логическое значение явным или неявным образом nullptr неизменно ложно? Эта реализация определена или указана в стандарте?

Я написал код для тестирования, но не уверен, полностью ли он проверяет это свойство. Я не смог найти существующего ответа SO, в котором говорилось бы конкретно об этом. cppreference не упоминает об этом из того, что я вижу.

if (nullptr) {
    ;
} else {
    std::cout << "Evaluates to false implicitly\n";
}

if (!nullptr) {
    std::cout << "Evaluates to false if operated on\n";
}

if (!(bool)(nullptr)) {
    std::cout << "Evaluates to false if explicitly cast to bool\n";
}

Ожидаемые и актуальные:

Evaluates to false implicitly
Evaluates to false if operated on
Evaluates to false if explicitly cast to bool

person David Thompson    schedule 16.08.2019    source источник
comment
stackoverflow.com/a/177007/8038186   -  person CoralK    schedule 16.08.2019
comment
Да, правда, cppreference этого не говорит. По крайней мере, не напрямую.   -  person Lightness Races in Orbit    schedule 16.08.2019
comment
nullptr неизменно ложно? - Да.   -  person Jesper Juhl    schedule 16.08.2019
comment
нашел здесь: en.cppreference.com/w/cpp/language/implicit_conversion и прокрутите вниз до §Булевы преобразования. Я согласен, что это следует упомянуть на en.cppreference.com/w/cpp/language/nullptr   -  person bolov    schedule 16.08.2019
comment
@bolov: Так что просто предложите там изменение, не нужно его здесь обсуждать ...   -  person einpoklum    schedule 19.08.2019
comment
@WalterNissen Falsy (также известный как falsey) - это не орфографическая ошибка. Это означает что-то вроде false при (неявном?) Преобразовании в bool.   -  person HolyBlackCat    schedule 12.09.2020
comment
@HolyBlackCat, я являюсь носителем английского языка, ложь - не обычное (и даже не редкое) слово. Это сленг в ограниченном сообществе. Лучше быть явным и использовать полностью развернутую фразу, как вы предоставили. Моя правка была однозначной, к этому надо стремиться.   -  person Walter Nissen    schedule 13.09.2020
comment
@WalterNissen Похоже, это в первую очередь термин JS, но я я видел, как это применимо к другим языкам (например, здесь). Is nullptr false - это немного двусмысленно, потому что nullptr не является bool с самого начала. Значение nullptr false при преобразовании в bool в порядке.   -  person HolyBlackCat    schedule 13.09.2020


Ответы (3)


Согласно стандарту C ++ 17 (литералы указателя 5.13.7)

1 Литерал указателя - это ключевое слово nullptr. Это значение типа std :: nullptr_t. [Примечание: std :: nullptr_t - это отдельный тип, который не является ни типом указателя, ни типом указателя на член; скорее, prvalue этого типа является константой нулевого указателя и может быть преобразовано в значение нулевого указателя или значение указателя на нулевой член. См. 7.11 и 7.12. - конец примечания]

И (7 стандартных преобразований)

4 Некоторые языковые конструкции требуют преобразования выражения в логическое значение. Выражение e, появляющееся в таком контексте, считается контекстно преобразованным в bool и является правильно сформированным тогда и только тогда, когда объявление bool t (e); имеет правильный формат для некоторой придуманной временной переменной t (11.6).

И наконец (7.14 булевых преобразований)

1 Значение арифметики, перечисления без области действия, указателя или типа указатель на член может быть преобразовано в значение типа bool. Нулевое значение, значение нулевого указателя или значение указателя нулевого члена преобразуется в ложное; любое другое значение преобразуется в истину. Для прямой инициализации (11.6) prvalue типа std :: nullptr_t может быть преобразовано в prvalue типа bool; результирующее значение ложно.

То есть вы можете написать например

bool b( nullptr );

но вы можете не писать (хотя в некоторых компиляторах есть ошибка, связанная с этим)

bool b = nullptr;

Таким образом, nullptr можно контекстно преобразовать в объект типа bool, например, в операторах выбора, таких как оператор if.

Рассмотрим, например, унарный оператор ! как в операторе if

if ( !nullptr ) { /*...*/ }

Согласно описанию оператора (8.5.2.1 Унарные операторы)

9 Операнд оператора логического отрицания! контекстно конвертируется в bool (пункт 7); его значение истинно, если преобразованный операнд ложно, и ложно в противном случае. Тип результата - bool

Таким образом, nullptr в этом выражении не преобразуется в указатель. Он напрямую контекстно конвертируется в bool.

person Vlad from Moscow    schedule 16.08.2019

Результат вашего кода гарантирован, [dcl.init] /17.8

В противном случае, если инициализация является прямой инициализацией, тип источника - std​::​nullptr_­t, а тип назначения - bool, начальное значение инициализируемого объекта - false.

Это означает, что для прямой инициализации объект bool может быть инициализирован из nullptr со значением результата false. Затем для (bool)(nullptr) nullptr преобразуется в bool со значением false.

При использовании nullptr в качестве условия if или операнда operator! он рассматривается как контекстные преобразования,

неявное преобразование выполняется, если объявление bool t(e); правильно сформировано

Это означает, что и if (nullptr), и !nullptr, nullptr будут преобразованы в bool со значением false.

person songyuanyao    schedule 16.08.2019
comment
Это неправильный ответ. std :: nullptr_t - это отдельный тип, который не является ни типом указателя, ни типом указателя на член. nullptr t - это константа нулевого указателя, которая может быть контекстно преобразована в bool. - person Vlad from Moscow; 16.08.2019

Да, но вам следует избегать использования этого факта.

Сравнение указателей с false или 0 - распространенный прием в кодировании C / C ++. Я предлагаю вам избегать его использования. Если вы хотите проверить нулевость, используйте:

if (x == nullptr) { /* ... */}

скорее, чем

if (!x) { /* ... */}

or

if (not x) { /* ... */}

Второй вариант вводит читателя в заблуждение: что такое x? Это логическое значение? Простое значение (например, целое число)? Указатель? Необязательный? Даже если x имеет значимое имя, это вам не очень поможет: if (!network_connection) ... это может быть сложная структура, конвертируемая в целое или логическое значение, это может быть логический индикатор наличия соединения, это может быть указатель, значение или необязательный. Или что-то другое.

Кроме того, помните, что nullptr оценивается как ложь - это еще один бит информации, который вам нужно хранить в задней части вашего мозга, чтобы правильно декодировать код, который вы читаете. Возможно, мы привыкли к этому с давних времен или читаем чужой код - но если бы мы не были, то не было бы очевидным, что nullptr ведет себя подобным образом. В некотором смысле это не отличается от других непонятных гарантий, например, как значение индекса 0 пустого std::string гарантированно будет _12 _ . Только не заставляйте свой код полагаться на это, если в этом нет крайней необходимости.


PS: На самом деле в наши дни использование нулевых указателей намного меньше. Вы можете заставить указатели никогда не быть нулевыми, если в этом нет необходимости; вы можете использовать ссылки вместо указателей; и вы можете использовать std::optional<T>, чтобы вернуть T или нет T. Возможно, вы могли бы просто вообще не упоминать nullptr.

person einpoklum    schedule 16.08.2019
comment
Я категорически не согласен с вашим советом. C о как и C ++ о что. Вот почему у вас есть auto: это означает, что вам не нужно знать тип. В той же строке if (!network_connection) ясно, и вам не нужно заботиться о том, является ли network_connection классом, конвертируемым в bool, или указателем. Код на C ++ должен выражать намерение программиста. - person Mirko; 16.08.2019
comment
@Mirko: Даже если вам интересно что, то не x все еще часто сбивает с толку. - person einpoklum; 17.08.2019