Безопасно ли проверять указатель на отсутствие NULL
написания просто if(pointer)
или я должен использовать if(pointer != NULL)
?
NULL
в C ++, потому что NULL
это макрос, зависящий от реализации, который может дать вам неоднозначное поведение.
Безопасно ли проверять указатель на отсутствие NULL
написания просто if(pointer)
или я должен использовать if(pointer != NULL)
?
NULL
в C ++, потому что NULL
это макрос, зависящий от реализации, который может дать вам неоднозначное поведение.
Ответы:
Ты можешь; нулевой указатель неявно преобразуется в логическое значение false, а ненулевые указатели преобразуются в истину. Из стандарта C ++ 11, раздел о булевых преобразованиях:
Значение арифметики, перечисление с незаданной областью, указатель или указатель на тип элемента может быть преобразовано в значение типа
bool
. Нулевое значение, нулевое значение указателя или нулевое значение указателя члена преобразуется вfalse
; любое другое значение преобразуется вtrue
. Значение типаstd::nullptr_t
может быть преобразовано в значение типаbool
; результирующее значениеfalse
.
Да, ты мог.
Это часть стандартного преобразования C ++, которое входит в условие преобразования Boolean :
§ 4.12. Булевы преобразования
Значение арифметики, перечисление с незаданной областью, указатель или указатель на тип члена может быть преобразовано в значение типа bool. Нулевое значение, нулевое значение указателя или нулевое значение указателя члена преобразуется в ложь; любое другое значение преобразуется в true. Значение типа std :: nullptr_t может быть преобразовано в значение типа bool; результирующее значение ложно.
Да, ты можешь. На самом деле, я предпочитаю использовать, if(pointer)
потому что читать и писать проще, когда вы к этому привыкнете.
Также обратите внимание, что в C ++ 11 введено, nullptr
что предпочтительнее, чем NULL
.
if(som_integer)
vs, if(some_integer != 0)
потому что целые числа также не булевы, верно? Я предпочитаю избегать 0
или NULL
в if-утверждении.
if (pointer)
себя, но мне if (ptr != nullptr)
кажется вполне законным. С другой стороны, если бы я увидел кого-то в моей команде, который написал, if (some_integer)
я бы заставил его изменить его if (some_integer != 0)
. Однако я не буду притворяться, что это не относительно произвольное предпочтение с моей стороны - я просто предпочитаю не обращаться с указателями и целыми числами одинаково.
if(isReady)
if(filePtr)
if(serviceNo)
? Создание неправильных имен переменных не имеет большого значения в этом случае. В любом случае, я уже понял вашу точку зрения и понял ее, но я могу сам настаивать на использовании своего собственного стиля кодирования, хорошо?
На вопрос дан ответ, но я бы хотел добавить свои очки.
Я всегда буду предпочитать 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)
что для меня более очевидно (показывает, что используется короткое замыкание).
(boolean expression)? true : false
совершенно бессмысленно. Выражение оценивает либо в, true
либо в false
; Вы говорите: «Если это правда, дай мне правду, если это ложь, дай мне ложь». Вкратце: это полностью эквивалентно самому логическому выражению. Обратите внимание, что node == NULL
это логическое выражение. Кстати, ваши две реализации возвращают в точности противоположные друг другу. Либо вы хотите !=
в первом, или только один !
во втором.
=
вместо того ==
, чтобы делать ваши переменные, const
когда это возможно. Например, вы можете определить свою функцию как isEmnpy(node* const head) { ... }
, и тогда компилятор откажется компилировать ее, если вы случайно написали node = NULL
вместо node == NULL
. Конечно, это работает только для переменных, которые вам не нужно менять.
T* get() const
вместо того, operator T*() const
чтобы избежать неявных преобразований. Однако они имеют operator bool() const
.
Да, ты можешь. Возможность неявно сравнивать значения с нулями была унаследована от 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
Хорошо, поэтому здесь не должно быть null ... ну, зачем это будет ноль? В то время как однострочная версия говорит очень просто: «Если вы можете безопасно привести 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(ptr)
а не то if(ptr != nullptr)
, на что есть что сказать.
Ну конечно; естественно! на самом деле запись if (указатель) является более удобным способом записи, чем if (pointer! = NULL), потому что: 1. это легко отладить 2. легко понять 3. если случайно, значение NULL определено, тогда и код не вылетит
Да. На самом деле вы должны. Если вам интересно, если это создает ошибку сегментации , это не так.
Как уже хорошо ответили другие, они оба взаимозаменяемы.
Тем не менее, стоит отметить , что может быть случай , когда вы можете использовать явное заявление, то есть pointer != NULL
.
Смотрите также https://stackoverflow.com/a/60891279/2463963
Да, вы всегда можете сделать это, поскольку условие «ЕСЛИ» оценивается только тогда, когда условие внутри него сбывается. C не имеет логического возвращаемого типа и, таким образом, возвращает ненулевое значение, когда условие истинно, и возвращает 0 всякий раз, когда условие в 'IF' оказывается ложным. Ненулевое значение, возвращаемое по умолчанию, равно 1. Таким образом, оба способа написания кода верны, а я всегда предпочитаю второй.
Я думаю, как правило, если ваше if-выражение может быть переписано как
const bool local_predicate = *if-expression*;
if (local_predicate) ...
так что это не вызывает никаких предупреждений, то это должно быть предпочтительным стилем для выражения if . (Я знаю, что получаю предупреждения, когда назначаю старый C BOOL
( #define BOOL int
) для C ++ bool
, не говоря уже о указателях.)
"Это безопасно..?" это вопрос о стандарте языка и сгенерированном коде.
"Это хорошая практика?" это вопрос о том, насколько хорошо это утверждение понято любым произвольным человеком, читающим это утверждение. Если вы задаете этот вопрос, это говорит о том, что «безопасная» версия менее понятна будущим читателям и писателям.
0
илиnullptr
. (NULL
является C'ism и требует включения заголовочного файла.)