web-dev-qa-db-fra.com

Utilisez-vous NULL ou (zéro) pour les pointeurs en C++?

Dans les premiers temps de C++, lorsqu'il était verrouillé au-dessus de C, vous ne pouviez pas utiliser NULL car il était défini par (void*)0. Vous ne pouviez pas affecter NULL à un pointeur autre que void*, ce qui le rendait plutôt inutile. À l'époque, il était admis que vous utilisiez 0 (zéro) pour les pointeurs nuls.

À ce jour, j'ai continué à utiliser zéro comme pointeur nul, mais ceux qui m'entourent insistent pour utiliser NULL. Personnellement, je ne vois aucun avantage à donner un nom (NULL) à une valeur existante - et comme j'aime aussi tester les pointeurs en tant que valeurs de vérité:

if (p && !q)
  do_something();

puis utiliser zéro a plus de sens (comme si vous utilisiez NULL, vous ne pouvez pas utiliser logiquement p && !q - vous devez explicitement comparer avec NULL, sauf si vous supposez que NULL est nul, auquel cas pourquoi utiliser NULL.

Existe-t-il une raison objective de préférer zéro à NULL (ou vice versa), ou s'agit-il uniquement d'une préférence personnelle?

Edit: Je devrais ajouter (et je voulais dire à l'origine) que, avec RAII et les exceptions, j'utilise rarement les pointeurs zéro/NULL, mais que parfois vous en avez encore besoin.

180
camh

Voici ce que Stroustrup a à dire: Style et technique C++ FAQ

En C++, la définition de NULL est 0, il n'y a donc qu'une différence esthétique. Je préfère éviter les macros et j'utilise donc 0. Un autre problème avec NULL est que les gens croient parfois à tort qu'il est différent de 0 et/ou non d'un entier. Dans le code pré-standard, NULL était/est parfois défini comme étant inadéquat et doit donc/doit être évité. C'est moins commun ces jours-ci.

Si vous devez nommer le pointeur null, appelez-le nullptr; c'est ce qu'on appelle en C++ 11. nullptr sera alors un mot clé. 

Cela dit, ne pas transpirer les petites choses.

168
Martin Cote

Il y a quelques arguments (dont l'un est relativement récent) qui, je crois, contredisent la position de Bjarne à ce sujet.

  1. Documentation d'intention

Utiliser NULL permet d'effectuer des recherches sur son utilisation et indique également que le développeur wanted doit utiliser un pointeur NULL, qu'il soit interprété par le compilateur comme étant NULL ou non.

  1. La surcharge du pointeur et de 'int' est relativement rare

L'exemple cité par tout le monde est:

void foo(int*);
void foo (int);

void bar() {
  foo (NULL);  // Calls 'foo(int)'
}

Cependant, du moins à mon avis, le problème avec ce qui précède n’est pas que nous utilisons NULL pour la constante du pointeur nul, mais bien que nous avons des surcharges de 'foo' qui prennent des types d’arguments très différents. Le paramètre doit également être int, car tout autre type entraîne un appel ambigu et génère donc un avertissement utile du compilateur.

  1. Les outils d'analyse peuvent aider AUJOURD'HUI!

Même en l'absence de C++ 0x, il existe aujourd'hui des outils permettant de vérifier que NULL est utilisé pour les pointeurs et que 0 est utilisé pour les types intégraux.

  1. C++ 11 aura un nouveau type std::nullptr_t.

Ceci est le dernier argument de la table. Le problème de 0 et NULL est activement traité pour C++ 0x, et vous pouvez garantir que pour chaque implémentation qui fournit NULL, la première chose à faire est la suivante:

#define NULL  nullptr

Pour ceux qui utilisent NULL au lieu de 0, le changement constituera une amélioration de la sécurité de type avec peu ou pas d'effort - il peut éventuellement attraper quelques bogues pour lesquels ils ont utilisé NULL pour 0. Pour ceux qui utilisent 0 aujourd'hui ... euh ... eh bien, espérons qu'ils aient une bonne connaissance des expressions régulières ...

117
Richard Corden

Utilisez NULL. NULL indique votre intention. Que ce soit 0 est un détail d'implémentation qui ne devrait pas avoir d'importance.

44
Andy Lester

J'utilise toujours:

  • NULL pour les pointeurs
  • '\0' pour les caractères
  • 0.0 pour les flotteurs et les doubles

où 0 ferait l'affaire. C'est une question d'intention de signalisation. Cela dit, je ne suis pas anal à ce sujet.

34
Andrew Stein

J'ai arrêté d'utiliser NULL en faveur de 0 depuis longtemps (ainsi que la plupart des autres macros). Je l'ai fait non seulement parce que je voulais éviter les macros autant que possible, mais aussi parce que NULL semble être devenu trop utilisé dans le code C et C++. Il semble être utilisé chaque fois qu'une valeur 0 est requise, pas seulement pour les pointeurs.

Sur les nouveaux projets, je mets cela dans un en-tête de projet:

static const int nullptr = 0;

Maintenant, lorsque les compilateurs conformes à C++ 0x arrivent, tout ce que je dois faire est de supprimer cette ligne . Un avantage intéressant est que Visual Studio reconnaît déjà nullptr en tant que mot clé et le met en évidence de manière appropriée.

34
Ferruccio
    cerr << sizeof(0) << endl;
    cerr << sizeof(NULL) << endl;
    cerr << sizeof(void*) << endl;

    ============
    On a 64-bit gcc RHEL platform you get:
    4
    8
    8
    ================

La morale de l'histoire. Vous devez utiliser NULL lorsque vous traitez avec des pointeurs.

1) Il déclare votre intention (ne me faites pas chercher dans tout votre code en essayant de déterminer si une variable est un pointeur ou un type numérique).

2) Dans certains appels d'API qui attendent des arguments variables, ils utiliseront un pointeur NULL pour indiquer la fin de la liste d'arguments. Dans ce cas, utiliser un '0' au lieu de NULL peut causer des problèmes. Sur une plate-forme 64 bits, l'appel va_arg demande un pointeur 64 bits, mais vous ne transmettez qu'un entier de 32 bits. Il me semble que vous vous fiez aux autres 32 bits pour être mis à zéro pour vous? J'ai vu certains compilateurs (par exemple, la société icpc d'Intel) qui ne sont pas aussi élégants - et cela a entraîné des erreurs d'exécution.

20
abonet

Si je me souviens bien, NULL est défini différemment dans les en-têtes que j'ai utilisés. Pour C, il est défini comme (void *) 0, et pour C++, il n'est défini que comme 0. Le code ressemblait à quelque chose comme:

#ifndef __cplusplus
#define NULL (void*)0
#else
#define NULL 0
#endif

Personnellement, j'utilise toujours la valeur NULL pour représenter les pointeurs nuls, cela indique clairement que vous utilisez un pointeur plutôt qu'un type intégral. Oui en interne, la valeur NULL est toujours 0 mais elle n'est pas représentée en tant que telle. 

De plus, je ne me base pas sur la conversion automatique d'entiers en valeurs booléennes, mais les compare explicitement.

Par exemple préférez utiliser:

if (pointer_value != NULL || integer_value == 0)

plutôt que:

if (pointer_value || !integer_value)

Il suffit de dire que tout cela est résolu en C++ 11, où l’on peut simplement utiliser nullptr au lieu de NULL, et aussi nullptr_t qui est le type de nullptr.

16
Daemin

Je dirais que l'histoire a parlé et que ceux qui ont préconisé l'utilisation de 0 (zéro) se sont trompés (y compris Bjarne Stroustrup). Les arguments en faveur de 0 étaient principalement esthétiques et "préférence personnelle".

Après la création de C++ 11, avec son nouveau type nullptr, certains compilateurs ont commencé à se plaindre (avec les paramètres par défaut) du passage de 0 à des fonctions avec des arguments de pointeur, car 0 n’est pas un pointeur. 

Si le code avait été écrit en utilisant NULL, une recherche et un remplacement simples auraient pu être effectués via la base de code pour le rendre nullptr à la place. Si vous êtes coincé avec du code écrit en utilisant le choix de 0 comme pointeur, il est beaucoup plus fastidieux de le mettre à jour.

Et si vous devez écrire un nouveau code dès maintenant au standard C++ 03 (et que vous ne pouvez pas utiliser nullptr), vous devez utiliser NULL. Il sera beaucoup plus facile pour vous de mettre à jour à l'avenir.

14
Gaute Lindkvist

J'ai déjà travaillé sur une machine où 0 était une adresse valide et NULL était défini comme une valeur octale spéciale. Sur cette machine (0! = NULL), code tel que

char *p;

...

if (p) { ... }

ne fonctionnerait pas comme prévu. Tu devais écrire 

if (p != NULL) { ... }

Bien que je pense que la plupart des compilateurs définissent NULL à 0 ces jours-ci, je me souviens encore de la leçon de ces années: NULL n’est pas nécessairement 0.

11
mxg

J'utilise habituellement 0. Je n'aime pas les macros et il n'y a aucune garantie qu'un en-tête tiers que vous utilisez ne redéfinit pas NULL pour qu'il soit étrange.

Vous pouvez utiliser un objet nullptr tel que proposé par Scott Meyers et d'autres jusqu'à ce que C++ obtienne un mot clé nullptr:

const // It is a const object...
class nullptr_t 
{
public:
    template<class T>
    operator T*() const // convertible to any type of null non-member pointer...
    { return 0; }

    template<class C, class T>
    operator T C::*() const   // or any type of null member pointer...
    { return 0; }

private:
    void operator&() const;  // Can't take address of nullptr

} nullptr = {};

Google "nullptr" pour plus d'informations.

11
jon-hanson

L'utilisation de 0 ou de NULL aura le même effet.

Cependant, cela ne veut pas dire que ce sont deux bonnes pratiques de programmation. Étant donné qu'il n'y a pas de différence de performance, choisir une option de bas niveau plutôt qu'une solution agnostique/abstraite est une mauvaise pratique de programmation. Aidez les lecteurs de votre code à comprendre votre processus de pensée

NULL, 0, 0.0, '\ 0', 0x00 et whatelse se traduisent tous par la même chose, mais sont des entités logiques différentes dans votre programme. Ils devraient être utilisés comme tels. NULL est un pointeur, 0 est une quantité, 0x0 est une valeur dont les bits sont intéressants, etc. Vous n'affecteriez pas '\ 0' à un pointeur qu'il soit compilé ou non.

Je sais que certaines communautés encouragent la démonstration d'une connaissance approfondie d'un environnement en rompant les contrats de l'environnement. Les programmeurs responsables créent toutefois du code maintenable et gardent ces pratiques hors de leur code.

9
Chris

Je pense que la norme garantit que NULL == 0, donc vous pouvez le faire. Je préfère NULL parce que cela documente votre intention.

9
Mark Ransom

Étrange, personne, y compris Stroustroup, n’a mentionné cela. En parlant beaucoup de normes et d’esthétique, personne n’a remarqué qu’il était dangereux d’utiliser 0 à la place de NULL, par exemple, dans la liste des arguments variables de l’architecture où sizeof(int) != sizeof(void*). Comme Stroustroup, je préfère 0 pour des raisons esthétiques, mais il faut faire attention de ne pas l'utiliser lorsque son type peut être ambigu.

5

J'essaie d'éviter toute la question en utilisant des références C++ lorsque cela est possible. Plutôt que

void foo(const Bar* pBar) { ... }

vous pourriez souvent être capable d'écrire

void foo(const Bar& bar) { ... }

Bien sûr, cela ne fonctionne pas toujours; mais les pointeurs nuls peuvent être surutilisés.

4
Ðаn

Je suis avec Stroustrup sur celui-ci: -) Puisque NULL ne fait pas partie du langage, je préfère utiliser 0.

3
Rob

La plupart du temps des préférences personnelles, bien que l’argument NULL indique clairement que l’objet est un pointeur qui ne pointe actuellement vers rien, par exemple.

void *ptr = &something;
/* lots o' code */
ptr = NULL; // more obvious that it's a pointer and not being used

IIRC, la norme n'exige pas que NULL soit égal à 0. Il est donc probablement préférable d'utiliser ce que vous définissez dans <stddef.h> pour votre compilateur.

Une autre facette de l’argument est de savoir si vous devez utiliser des comparaisons logiques (conversion implicite en bool) ou une vérification d’explicités contre NULL, mais cela se résume également à la lisibilité.

3
Jimmy

Je préfère utiliser NULL car il est clair que votre intention est que la valeur représente un pointeur et non une valeur arithmétique. Le fait qu’il s’agisse d’une macro est regrettable, mais comme elle est si profondément enracinée, il ya peu de danger (sauf si quelqu'un fait quelque chose de vraiment stupide). J'aimerais que ce soit un mot-clé depuis le début, mais que pouvez-vous faire?

Cela dit, je n'ai aucun problème à utiliser les pointeurs comme valeurs de vérité en eux-mêmes. Tout comme avec NULL, c'est un idiome enraciné.

C++ 09 ajoutera la construction nullptr qui, je pense, est attendue depuis longtemps. 

3
Michael Burr

J'utilise toujours 0. Pas pour une raison vraiment réfléchie, simplement parce que lorsque j'ai appris le C++, j'ai lu quelque chose qui recommandait d'utiliser 0 et que je viens de faire de cette façon. En théorie, il pourrait y avoir un problème de lisibilité au niveau de la lisibilité, mais en pratique, je n'ai jamais rencontré un tel problème en milliers d'heures de travail et en millions de lignes de code. Comme le dit Stroustrup, ce n’est vraiment qu’un problème d’esthétique personnel jusqu’à ce que la norme devienne nulle.

1
Gerald

Quelqu'un m'a dit une fois ... Je vais redéfinir NULL à 69. Depuis, je ne l'utilise plus: P

Cela rend votre code assez vulnérable.

Modifier:

Tout dans la norme n'est pas parfait. La macro NULL est une constante de pointeur null C++ définie par l’implémentation qui n’est pas entièrement compatible avec la macro C NULL. Outre le masque qui le masque implicitement, elle est convertie en outil inutile et sujet aux erreurs. 

NULL ne se comporte pas comme un pointeur null mais comme un littéral O/OL. 

Dites-moi que l'exemple suivant n'est pas déroutant: 

void foo(char *); 
void foo(int); 
foo(NULL); // calls int version instead of pointer version! 

C’est à cause de tout cela que la nouvelle norme apparaît std :: nullptr_t

Si vous ne voulez pas attendre la nouvelle norme et souhaitez utiliser un nullptr, utilisez au moins un modèle décent comme celui proposé par Meyers (voir le commentaire jon.h).

Eh bien, je préconise de ne pas utiliser de pointeurs 0 ou NULL autant que possible.

Leur utilisation conduira tôt ou tard à des erreurs de segmentation dans votre code. D'après mon expérience, ceci et les pointeurs généraux sont l'une des plus grandes sources de bogues en C++

cela conduit également à des déclarations "if-not-null" sur tout votre code. Bien plus agréable si vous pouvez toujours compter sur un état valide.

Il y a presque toujours une meilleure alternative.

1
Jan P