Чи безпечно перевіряти вказівник на те, що він не NULL
пише, просто if(pointer)
чи потрібно використовувати if(pointer != NULL)
?
NULL
C ++ з цього приводу, тому що NULL
макрос залежний від реалізації, який може викликати неоднозначне поведінку.
Чи безпечно перевіряти вказівник на те, що він не NULL
пише, просто if(pointer)
чи потрібно використовувати if(pointer != NULL)
?
NULL
C ++ з цього приводу, тому що NULL
макрос залежний від реалізації, який може викликати неоднозначне поведінку.
Відповіді:
Ти можеш; нульовий покажчик неявно перетворюється на булеву помилку, тоді як ненульові покажчики перетворюються на істинні. Зі стандарту C ++ 11, розділ " Булеві перетворення":
Первинне значення арифметичного, нескопаного перерахування, вказівника або вказівника на тип члена може бути перетворене в перше значення типу
bool
. Нульове значення, нульове значення вказівника або значення вказівника нульового члена перетворюється вfalse
; будь-яке інше значення перетворюється вtrue
. Первісне значення типуstd::nullptr_t
може бути перетворене в первісне значення типуbool
; отримане значення дорівнюєfalse
.
Так, ви могли.
Це частина стандартної конверсії C ++, яка впадає в булеву статтю перетворення :
§ 4.12 Булеві перетворення
Первісне значення арифметичного, нескопаного перерахування, вказівника або вказівника на тип члена може бути перетворене в перше значення типу bool. Нульове значення, нульове значення вказівника або значення вказівника нульового члена перетворюється на помилкове; будь-яке інше значення перетворюється на істинне. Первісне значення типу 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
тут не повинно бути нульовим ... ну чому б це буде нульовим? " В той час, як однолінійна версія дуже чітко говорить: "Якщо ви можете сміливо 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 (покажчик) є більш зручним способом написання, а не якщо (покажчик! = NULL), тому що: 1. це легко налагодити 2. легко зрозуміти 3. якщо випадково визначено значення NULL, тоді і код не вийде з ладу
Так. Насправді слід. Якщо вам цікаво, чи це створює помилку сегментації , це не так.
Як вже добре відповіли інші, вони обоє взаємозамінні.
Тим не менше, варто згадати, що може бути випадок, коли ви можете скористатися явним твердженням, тобто pointer != NULL
.
Дивіться також https://stackoverflow.com/a/60891279/2463963
Так, ви завжди можете це зробити так, як "IF" умова оцінюється лише тоді, коли умова всередині неї справдиться. 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, і вимагає включити файл заголовка.)