Est-il prudent de vérifier un pointeur pour ne pas être NULL
en écrivant simplement if(pointer)
ou dois-je utiliser if(pointer != NULL)
?
Vous pouvez; le pointeur null est implicitement converti en boolean false tandis que les pointeurs non null sont convertis en true. Du standard C++ 11, section sur Conversions booléennes:
Une valeur prédéfinie d'arithmétique, une énumération non réduite, un pointeur ou un pointeur sur un type de membre peut être convertie en un prvalue de type
bool
. Une valeur nulle, une valeur de pointeur nulle ou une valeur de pointeur de membre nul est convertie enfalse
; toute autre valeur est convertie entrue
. Une valeur de typestd::nullptr_t
peut être converti en une valeur de typebool
; la valeur résultante estfalse
.
Oui vous pourriez.
Cela fait partie de la conversion standard C++, qui relève de la clause Boolean conversion:
§ 4.12 Conversions booléennes
Une valeur prédéfinie d'arithmétique, énumération non rognée, pointeur , ou un pointeur sur un type de membre peut être convertie en une valeur de type bool. Une valeur nulle, une valeur de pointeur nulle ou une valeur de pointeur de membre nul est convertie en false; toute autre valeur est convertie en true. Une valeur de type std :: nullptr_t peut être convertie en une valeur de type bool; la valeur résultante est false.
Oui, vous pouvez. En fait, je préfère utiliser if(pointer)
car il est plus simple de lire et d’écrire une fois que vous vous y êtes habitué.
Notez également que C++ 11 a introduit nullptr
, qui est préférable à NULL
.
La question est répondue, mais je voudrais ajouter mes points.
Je préférerai toujours if(pointer)
au lieu de if(pointer != NULL)
et if(!pointer)
au lieu de if(pointer == NULL)
:
Moins de chances d'écrire un code buggy, supposons si j'ai mal orthographié l'opérateur de contrôle d'égalité ==
avec =
if(pointer == NULL)
peut être mal orthographié if(pointer = NULL)
Donc, je vais l'éviter, le mieux est simplement if(pointer)
.
(J'ai aussi suggéré une condition Yoda dans une réponse , mais c'est différent
De même pour while (node != NULL && node->data == key)
, j'écrirai simplement while (node && node->data == key)
qui m'est plus évident (montre que l'utilisation d'un court-circuit).
Oui, vous pouvez. La possibilité de comparer implicitement des valeurs à des zéros a été héritée de C et existe dans toutes les versions de C++. Vous pouvez également utiliser if (!pointer)
pour vérifier les pointeurs pour NULL.
Les cas d'utilisation pertinents pour les pointeurs nuls sont
Dynamique jette. Le fait de fondre un pointeur de classe de base sur un pointeur de classe dérivée particulier (ce que vous devriez à nouveau essayer d'éviter, mais que vous jugez parfois nécessaire) réussit toujours, mais aboutit à un pointeur nul si la classe dérivée ne correspond pas. Une façon de vérifier c'est
Derived* derived_ptr = dynamic_cast<Derived*>(base_ptr);
if(derived_ptr != nullptr) { ... }
(ou, de préférence, auto derived_ptr = ...
). Maintenant, ceci est mauvais, car il laisse le pointeur dérivé (éventuellement non valide, null) en dehors du champ du bloc de sécurité if
. Ce n'est pas nécessaire, car C++ vous permet d'introduire des variables booléennes convertibles dans une variable if
- :
if(auto derived_ptr = dynamic_cast<Derived*>(base_ptr)) { ... }
ce qui est non seulement plus court et sûr, mais aussi beaucoup plus clair dans son intention: lorsque vous recherchez la valeur null dans une condition if distincte, le lecteur se demande "ok, donc derived_ptr
ne doit pas être null ici ... eh bien, pourquoi serait-il nul? " Alors que la version à une ligne dit très clairement "si vous pouvez transtyper base_ptr
en Derived*
en toute sécurité, utilisez-le pour ...".
La même chose fonctionne aussi bien pour toute autre opération d'échec possible qui retourne un pointeur, mais IMO évite généralement ceci: il est préférable d'utiliser quelque chose comme boost::optional
en tant que "conteneur" pour les résultats d'opérations éventuellement en échec, plutôt que des pointeurs.
Donc, si le cas d'utilisation principal pour les pointeurs nuls doit toujours être écrit dans une variante du style de diffusion implicite, je dirais que c'est bien pour des raisons de cohérence d'utiliser toujours utiliser ce style, c'est-à-dire if(ptr)
sur if(ptr!=nullptr)
.
J'ai bien peur de devoir terminer par une publicité: la syntaxe if(auto bla = ...)
n'est en réalité qu'une approximation un peu lourde de la solution real à ces problèmes: pattern matching . Pourquoi voudriez-vous d'abord forcer une action (comme lancer un pointeur) et ensuite considérer qu'il pourrait y avoir un échec ... Je veux dire, c'est ridicule, n'est-ce pas? C'est comme si tu avais des aliments et que tu voulais faire de la soupe. Vous le remettez à votre assistant avec la tâche d'extraire le jus, s'il s'agit d'un légume doux. Vous ne le regardez pas d'abord. Quand vous avez une pomme de terre, vous la donnez toujours à votre assistant, mais il vous la gifle avec une note d'échec. Ah, la programmation impérative!
Bien mieux: considérez tout de suite tous les cas que vous pourriez rencontrer. Alors agissez en conséquence. 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 dispose également d'outils spéciaux pour les cas où il existe une possibilité sérieuse d'échec (ainsi que pour tout un tas d'autres éléments): les monades. Mais ce n’est pas le lieu d’expliquer cela.
⟨/publicité⟩
Oui. En fait, vous devriez. Si vous vous demandez s'il crée une erreur segmentation , ce n'est pas le cas.
oui bien sûr! en fait, écrire si (pointeur) est un moyen plus pratique d’écrire que si (pointeur! = NULL) car: il est facile de déboguer 2. facile à comprendre 3. si accidentellement, la valeur de NULL est définie, le code ne plantera pas non plus