Могу ли я использовать if (указатель) вместо if (указатель!= NULL)?

Безопасно ли проверять указатель на отсутствие NULL просто написав if(pointer) или я должен использовать if(pointer != NULL)?

12 ответов

Решение

Вы можете; нулевой указатель неявно преобразуется в логическое значение false, а ненулевые указатели преобразуются в значение true. Из стандарта C++11, раздел о булевых преобразованиях:

Значение арифметики, перечисление с незаданной областью, указатель или указатель на тип элемента может быть преобразовано в значение типа bool, Нулевое значение, нулевое значение указателя или нулевое значение указателя члена преобразуется в false; любое другое значение преобразуется в true, Prvalue типа std::nullptr_t может быть преобразовано в тип значения bool; результирующее значение false,

Да, ты мог.

  • Пустой указатель неявно преобразуется в ложный
  • ненулевой указатель преобразуется в true.

Это часть стандартного преобразования C++, которое входит в условие преобразования Boolean:

§ 4.12. Булевы преобразования

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

Да, ты можешь. На самом деле, я предпочитаю использовать if(pointer) потому что читать и писать легче, когда вы к этому привыкнете.

Также обратите внимание, что C++11 введен nullptr который предпочтительнее NULL,

На вопрос дан ответ, но я бы хотел добавить свои очки.

Я всегда предпочитаю if(pointer) вместо if(pointer != NULL) а также if(!pointer) вместо if(pointer == NULL):

  • Это просто, маленький
  • Меньше шансов написать глючный код, предположим, что если я неправильно написал оператор проверки равенства == с =
    if(pointer == NULL) может быть с ошибкой if(pointer = NULL) Так что я буду избегать этого, лучше всего if(pointer),
    (Я также предложил некоторые условия Йоды в одном ответе, но это разные вопросы)

  • Аналогично для while (node != NULL && node->data == key), Я просто напишу while (node && node->data == key) это более очевидно для меня (показывает, что с помощью короткого замыкания).

  • (может быть глупой причиной) Поскольку NULL - это макрос, если предположить, что кто-то один переопределил по ошибке с другим значением.

Явная проверка на NULL может дать подсказку компилятору о том, что вы пытаетесь сделать, что приводит к меньшей подверженности ошибкам.

Да, ты можешь. Возможность неявно сравнивать значения с нулями была унаследована от C и присутствует во всех версиях C++. Вы также можете использовать if (!pointer) проверить указатели на NULL.

Соответствующие варианты использования для нулевых указателей

  • Перенаправление на что-то вроде более глубокого узла дерева, который может не существовать или еще не был связан. Это то, что вы всегда должны хранить в отдельности в отдельном классе, поэтому удобочитаемость или краткость не являются большой проблемой.
  • Динамические броски. Приведение указателя базового класса к конкретному производному классу (то, что вы должны снова попытаться избежать, но иногда может оказаться необходимым) всегда завершается успешно, но приводит к нулевому указателю, если производный класс не совпадает. Один из способов проверить это

    Derived* derived_ptr = dynamic_cast<Derived*>(base_ptr);
    if(derived_ptr != nullptr) { ... }
    

    (или, предпочтительно, auto derived_ptr = ...). Теперь это плохо, потому что он оставляет (возможно, недействительный, то есть нулевой) производный указатель за пределами безопасности if область применения блока В этом нет необходимости, поскольку C++ позволяет вводить переменные, логически конвертируемые внутри if условие:

    if(auto derived_ptr = dynamic_cast<Derived*>(base_ptr)) { ... }
    

    который не только короче и безопаснее по объему, но и гораздо более понятен в своем намерении: когда вы проверяете на null в отдельном условии if, читатель задается вопросом: "Хорошо, так derived_ptr не должно быть нулевым здесь... ну, почему это будет нулевым?"В то время как однострочная версия говорит очень просто", если вы можете безопасно разыграть base_ptr в Derived*, а затем использовать его для...".

    То же самое работает и для любой другой операции возможного сбоя, которая возвращает указатель, хотя IMO, как правило, следует избегать этого: лучше использовать что-то вроде boost::optional как "контейнер" для результатов возможных неудачных операций, а не указатели.

Итак, если основной сценарий использования нулевых указателей всегда должен быть написан в варианте неявного стиля приведения, я бы сказал, что по соображениям согласованности всегда следует использовать этот стиль, т.е. if(ptr) над if(ptr!=nullptr),


Боюсь, мне нужно закончить рекламой: if(auto bla = ...) синтаксис на самом деле является лишь немного громоздким приближением к реальному решению таких проблем: сопоставление с образцом. Зачем вам сначала предпринимать какие-то действия (например, приведение указателя), а затем подумать, что может произойти сбой... Я имею в виду, это смешно, не правда ли? Как будто у тебя есть продукты и ты хочешь приготовить суп. Вы передаете его своему помощнику с задачей извлечь сок, если он окажется мягким овощем. Вы сначала не смотрите на это. Когда у вас есть картошка, вы все равно отдаете ее своему помощнику, но они бьют ее по лицу с запиской об ошибке. Ах, императивное программирование!

Намного лучше: рассмотрите сразу все случаи, с которыми вы можете столкнуться. Тогда действуй соответственно. Haskell:

makeSoupOf :: Foodstuff -> Liquid
makeSoupOf p@(Potato{..}) = mash (boil p) <> water
makeSoupOf vegetable
 | isSoft vegetable  = squeeze vegetable <> salt
makeSoupOf stuff  = boil (throwIn (water<>salt) stuff)

На Haskell также есть специальные инструменты для случаев, когда существует серьезная вероятность отказа (как и для целого ряда других вещей): монады. Но это не место для объяснения этого.

⟨/объявление⟩

Да, конечно! на самом деле запись if(указатель) является более удобным способом записи, чем if(pointer!= NULL), потому что: 1. это легко отладить 2. легко понять 3. если случайно, значение NULL определено, тогда и код не вылетит

Да, оба функционально одно и то же. Но в C++ вы должны переключиться на nullptr вместо NULL;

Да. На самом деле вы должны. Если вам интересно, создает ли он ошибку сегментации, это не так.

"Это безопасно..?" это вопрос о стандарте языка и сгенерированном коде.

"Это хорошая практика?" это вопрос о том, насколько хорошо это утверждение понято любым произвольным человеком, читающим это утверждение. Если вы задаете этот вопрос, это говорит о том, что "безопасная" версия менее понятна будущим читателям и писателям.

Я думаю, как правило, если ваше выражение if можно переписать как

const bool local_predicate = *if-expression*;
if (local_predicate) ...

так что это не вызывает никаких предупреждений, то это должно быть предпочтительным стилем для выражения if. (Я знаю, что я получаю предупреждения, когда я назначаю старый C BOOL (#define BOOL int) к C++ boolне говоря уже о указателях.)

Да, вы всегда можете сделать это, так как условие 'IF' оценивается только тогда, когда условие внутри него становится истинным. C не имеет логического возвращаемого типа и, таким образом, возвращает ненулевое значение, когда условие истинно, а возвращает 0 всякий раз, когда условие в 'IF' оказывается ложным. Ненулевое значение, возвращаемое по умолчанию, равно 1. Таким образом, оба способа написания кода верны, а я всегда предпочитаю второй.

Как уже хорошо ответили другие, они оба взаимозаменяемы.

Тем не менее, стоит упомянуть, что может быть случай, когда вы захотите использовать явный оператор, т.е. pointer != NULL.

См. Также /questions/11783092/raznitsa-mezhdu-ifukazatel-i-ifukazatel-null-v-c-problema-cpplint/55351740#55351740

Другие вопросы по тегам