Могу ли я использовать 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
.