Puis-je utiliser if (pointer) au lieu de if (pointer! = NULL)?


171

Est-il sûr de vérifier un pointeur pour ne pas être NULLen écrivant simplement if(pointer)ou dois-je utiliser if(pointer != NULL)?


13
La vérité est que si vous utilisez une vérification explicite, il est tout aussi efficace - et souvent préféré - de tester contre 0ou nullptr. ( NULLest un C'ism, et nécessite d'inclure un fichier d'en-tête.)
cHao

5
@danijar Vous pouvez utiliser nullptr dans le C ++ moderne.
SurvivalMachine

9
@cHao Où est l'intérêt de "viser la compatibilité avec C"?
qdii

5
@danijar: Oui, vous ne devriez pas utiliser NULLen C ++ à partir de maintenant car NULLc'est une macro dépendante de l'implémentation qui peut vous donner des comportements ambigus.
Alok Sauvegardez le

3
Bien que ce ne soit pas le cas 'if', voyez cette démo en direct d'ideone pour savoir pourquoi vous devriez éviter "NULL" et "0" pour les pointeurs en C ++: ideone.com/tbvXNs
kfsone

Réponses:


198

Vous pouvez; le pointeur nul est implicitement converti en booléen faux tandis que les pointeurs non nuls sont convertis en vrai. De la norme C ++ 11, section sur les conversions booléennes:

Une prvalue d'arithmétique, une énumération sans portée, un pointeur ou un pointeur vers un type de membre peut être convertie en une prvalue de type bool. Une valeur zéro, une valeur de pointeur null ou une valeur de pointeur de membre nul est convertie en false; toute autre valeur est convertie en true . Une prvalue de type std::nullptr_t peut être convertie en une prvalue de type bool ; la valeur résultante est false .


42

Oui vous pourriez.

  • Un pointeur nul est converti en faux implicitement
  • un pointeur non nul est converti en vrai.

Cela fait partie de la conversion standard C ++, qui relève de la clause de conversion booléenne :

§ 4.12 Conversions booléennes

Une prvalue d'arithmétique, une énumération sans portée, un pointeur ou un pointeur vers un type de membre peut être convertie en une prvalue de type bool. Une valeur zéro, une valeur de pointeur null ou une valeur de pointeur de membre nul est convertie en false; toute autre valeur est convertie en vrai. Une prvalue de type std :: nullptr_t peut être convertie en une prvalue de type bool; la valeur résultante est fausse.


29

Oui, vous pouvez. En fait, je préfère l'utiliser if(pointer)car c'est plus simple à lire et à écrire une fois que vous vous y êtes habitué.

Notez également que C ++ 11 a introduit nullptrce qui est préféré à NULL.


10
Un pointeur n'est pas une expression booléenne. Il est converti implicitement. S'il est préférable de lire lorsque vous devez vous souvenir de cette conversion pour comprendre, c'est votre opinion. C'est juste un type de style de codage.
harper

7
@harper Vous pouvez dire que c'est un style de codage. Mais vous pouvez appliquer la même logique à if(som_integer)vs if(some_integer != 0)car les entiers ne sont pas non plus des booléens, non? Je préfère éviter 0ou NULLdans une déclaration if.
Yu Hao

13
Je conviens que c'est simplement une question de style de codage. J'en suis venu à if (pointer)me préférer , mais me if (ptr != nullptr)semble parfaitement légitime. D'un autre côté, si je voyais quelqu'un de mon équipe qui écrivait, if (some_integer)je le ferais changer en if (some_integer != 0). Cependant, je ne prétendrai pas que ce n'est pas une préférence relativement arbitraire de ma part - je préfère simplement ne pas traiter les pointeurs et les entiers de la même manière.
Joel

1
@YuHao Et comme c'est un style de code, je ne dirais pas "c'est préféré" mais "je préfère".
harper

5
@ franji1 Alors qu'en est-il if(isReady) if(filePtr) if(serviceNo)? Faire exprès de mauvais noms de variables ne signifie pas grand-chose dans ce cas. Quoi qu'il en soit, j'ai déjà compris votre point de vue et je l'ai compris, mais je peux insister moi-même en utilisant mon propre style de codage, d'accord?
Yu Hao

13

La question a reçu une réponse, mais je voudrais ajouter mes points.

Je préférerai toujours if(pointer)au lieu if(pointer != NULL)et if(!pointer)au lieu de if(pointer == NULL):

  • C'est simple, petit
  • Moins de chances d'écrire un code bogué, supposons que si j'ai mal orthographié l'opérateur de vérification d'égalité ==avec =
    if(pointer == NULL)peut être mal orthographié if(pointer = NULL)Donc je vais l'éviter, le mieux est juste if(pointer).
    (J'ai également suggéré une condition Yoda en une seule réponse , mais c'est une question différente)

  • De même pour while (node != NULL && node->data == key), j'écrirai simplement ce while (node && node->data == key)qui est plus évident pour moi (montre que l'utilisation de court-circuit).

  • (peut être une raison stupide) Parce que NULL est une macro, si supposons que quelqu'un redéfinisse par erreur avec une autre valeur.

6
Utiliser = au lieu de == génère presque toujours un avertissement du compilateur, à l'époque où ce n'était pas le cas, les gens utilisaient if (NULL == ptr)
paulm

@paulm que je viens d'ajouter ce point s'appelle Yoda Condition, certaines personnes ne l'aiment pas car c'est moins lisible.
Grijesh Chauhan

2
(boolean expression)? true : falseest complètement inutile. L'expression évalue à trueou à false; ce que vous dites, c'est "si c'est vrai, donnez-moi vrai, si c'est faux, donnez-moi faux". En bref: c'est complètement équivalent à l'expression booléenne elle-même. Notez qu'il node == NULLs'agit d'une expression booléenne. BTW, vos deux implémentations renvoient exactement le contraire l'une de l'autre. Soit vous voulez !=dans le premier, soit un seul !dans le second.
celtschk

BTW, une protection possible contre =au lieu de ==est de rendre vos variables constchaque fois que possible. Par exemple, vous pouvez définir votre fonction comme isEmnpy(node* const head) { ... }, et le compilateur refuserait de la compiler si vous écriviez accidentellement à la node = NULLplace de node == NULL. Bien sûr, cela ne fonctionne que pour les variables que vous n'avez vraiment pas besoin de modifier.
celtschk

2
Parce que les classes de pointeur intelligent ont T* get() constau lieu de operator T*() constpour éviter les conversions implicites. Ils ont cependant un operator bool() const.
StellarVortex

13

La vérification explicite de NULL pourrait fournir un indice au compilateur sur ce que vous essayez de faire, ce qui conduit à être moins sujet aux erreurs.

entrez la description de l'image ici


8

Oui, vous pouvez. La possibilité de comparer des valeurs à des zéros implicitement a été héritée de C et est présente dans toutes les versions de C ++. Vous pouvez également utiliser if (!pointer)pour vérifier les pointeurs pour NULL.


2

Les cas d'utilisation pertinents pour les pointeurs nuls sont

  • Redirection vers quelque chose comme un nœud d'arbre plus profond, qui peut ne pas exister ou n'a pas encore été lié. C'est quelque chose que vous devriez toujours garder étroitement encapsulé dans une classe dédiée, donc la lisibilité ou la concision n'est pas un problème ici.
  • Des lancers dynamiques. Le cast d'un pointeur de classe de base vers une classe dérivée particulière (quelque chose que vous devriez à nouveau essayer d'éviter, mais que vous pourriez parfois trouver 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 cela est

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

    (ou, de préférence, auto derived_ptr = ...). Maintenant, c'est mauvais, car cela laisse le pointeur dérivé (peut-être invalide, c'est-à-dire nul) en dehors de la ifportée du bloc de sécurité . Ce n'est pas nécessaire, car C ++ vous permet d'introduire des variables convertibles booléennes dans une if-condition :

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

    ce qui est non seulement plus court et sûr pour la portée, mais aussi beaucoup plus clair dans son intention: lorsque vous vérifiez null dans une condition if séparée, le lecteur se demande "ok, donc derived_ptrne doit pas être nul ici ... eh bien, pourquoi le ferait il est nul? " Alors que la version d' une ligne dit très clairement « si vous pouvez en toute sécurité jeté base_ptrà Derived*, puis l ' utiliser ... ».

    La même chose fonctionne aussi bien pour toute autre opération d'échec possible qui retourne un pointeur, même si IMO vous devriez généralement éviter ceci: il est préférable d'utiliser quelque chose comme boost::optionalle "conteneur" pour les résultats d'opérations éventuellement échouées, plutôt que des pointeurs.

Donc, si le cas d'utilisation principal des pointeurs nuls doit toujours être écrit dans une variante du style implicite-cast, je dirais qu'il est bon pour des raisons de cohérence de toujours utiliser ce style, c'est-à-dire que je recommanderais if(ptr)plus if(ptr!=nullptr).


J'ai bien peur de devoir terminer par une annonce: la if(auto bla = ...)syntaxe n'est en fait qu'une approximation un peu lourde de la vraie solution à de tels problèmes: la correspondance de motifs . 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 vous aviez de la nourriture et que vous vouliez faire de la soupe. Vous le donnez à votre assistant avec la tâche d'extraire le jus, s'il s'agit d'un légume mou. Vous ne le regardez pas d'abord. Lorsque vous avez une pomme de terre, vous la donnez toujours à votre assistant, mais il vous la claque au visage avec une note d'échec. Ah, 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 a également des outils spéciaux pour les cas où il y a vraiment une sérieuse possibilité d'échec (ainsi que pour tout un tas d'autres choses): les monades. Mais ce n'est pas le lieu pour les expliquer.

⟨/publicité⟩


1
Je ne vois qu'une phrase dans cette chape interminable qui répond en fait à la question.
Marquis of Lorne

@EJP: si vous prenez la question au pied de la lettre (" puis- je utiliser"), alors elle ne répond pas du tout explicitement (la réponse est simplement "oui"). J'ai essayé de donner des raisons appropriées pour lesquelles le PO devrait en fait utiliser if(ptr)plutôt que if(ptr != nullptr), sur lesquelles il y a un peu plus à dire.
gauche autour du

1

Oui bien sûr! en fait, écrire if (pointer) est un moyen plus pratique d'écrire que if (pointer! = NULL) car: 1. il est facile à déboguer 2. facile à comprendre 3. si accidentellement, la valeur de NULL est définie, alors aussi le code ne plantera pas



0

Comme d'autres ont déjà bien répondu, ils sont tous deux interchangeables.

Néanmoins, il convient de mentionner qu'il pourrait y avoir un cas où vous voudrez peut-être utiliser l'instruction explicite, ie pointer != NULL .

Voir également https://stackoverflow.com/a/60891279/2463963


-1

Oui, vous pouvez toujours le faire car la condition 'IF' s'évalue uniquement lorsque la condition à l'intérieur devient vraie. C n'a pas de type de retour booléen et renvoie donc une valeur non nulle lorsque la condition est vraie, tandis que renvoie 0 chaque fois que la condition dans 'IF' s'avère être fausse. La valeur non nulle renvoyée par défaut est 1. Ainsi, les deux manières d'écrire le code sont correctes alors que je préférerai toujours la seconde.


1
La valeur non nulle par défaut n'est pas définie si je me souviens bien.
Marquis of Lorne

-1

Je pense qu'en règle générale, si votre expression if peut être réécrite comme

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

tel qu'il ne provoque AUCUN AVERTISSEMENT, alors THAT doit être le style préféré pour l' expression if . (Je sais que je reçois des avertissements lorsque j'attribue un ancien C BOOL( #define BOOL int) à un C ++ bool, sans parler des pointeurs.)


-1

"Est-ce sûr..?" est une question sur le standard du langage et le code généré.

"Est-ce une bonne pratique?" est une question sur la façon dont la déclaration est comprise par tout lecteur humain arbitraire de la déclaration. Si vous posez cette question, cela suggère que la version "sûre" est moins claire pour les futurs lecteurs et écrivains.


Mon intention était de demander si c'est sûr. J'ai donc utilisé ce libellé. Cependant, ce que vous avez écrit ici n'est pas une réponse à la question. Au lieu de cela, cela devrait être un commentaire sous la question. Vous pouvez alors supprimer la réponse et ajouter un commentaire sous la question.
danijar

@danijar Vous ne vous souvenez pas quand vous étiez nouveau sur StackOverflow et que vous avez recherché la section «Commentaire» sans succès? Quelqu'un de réputation ne peut pas faire ça.
Broxzier

@JimBalter Ce qui est très déroutant, car vous pouvez voir les autres le faire. Quand j'étais nouveau dans SO, quelqu'un m'a reproché de faire ça.
Broxzier

@JimBalter Je ne suis pas en train de tuer et de voler. Je disais à danijar que Fred Mitchell était un nouvel utilisateur et ne pouvait pas publier de commentaires.
Broxzier

@JimBalter Ce que vous avez commencé aujourd'hui. Vous êtes aussi celui qui ne comprend pas à la place. Ce commentaire ne fait que soutenir la confusion de cela.
Broxzier
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.