Dans C++ 11, le mot clé nullptr
a été ajouté en tant que constante de pointeur null de type plus sûr, car la précédente définition commune de NULL
as 0 a quelques problèmes.
Pourquoi le comité des normes a-t-il choisi de ne pas appeler la nouvelle constante de pointeur nul NULL
, ou de déclarer que NULL
devrait être #define
d à nullptr
?
Stephan T. Lavavej (membre du comité standard C++) a expliqué qu'une fois dans un talk (55:35):
Alors qu'une implémentation est autorisée à #define NULL nullptr
, cela casserait pas mal d'utilisations comme
int i = NULL;
et apparemment il y en a beaucoup. Ils ne pouvaient donc pas forcer le changement.
nullptr
est de type pointeur , tandis que NULL
a tendance à être entier, et parfois dans les fonctions surchargées, vous besoin d'être clair que vous utilisez un pointeur et non un entier - c'est quand nullptr
est utile.
Donc, pour vraiment répondre à votre question, NULL
et nullptr
ont deux fonctions différentes et la redéfinition l'une de l'autre cassera probablement beaucoup de choses dans les bases de code déjà existantes.
À côté de cela, vérifiez cela depuis site Web de Bjarne Stroustrup :
Dois-je utiliser NULL ou 0?
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, donc j'utilise 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 sur quelque chose d'inadapté et devait/doit donc être évité. C'est moins courant de nos jours. Si vous devez nommer le pointeur nul, appelez-le nullptr; c'est ce qu'on appelle en C++ 11. Ensuite, "nullptr" sera un mot-clé.
Sans vraiment participer à la discussion au sein du comité des normes, il est difficile de dire avec certitude, mais je pense que cela casserait un code qui utilise NULL
dans un sens où nullptr
n'est pas suffisamment compatible. Et briser l'ancien code n'est jamais une bonne idée.
NULL
n'est pas de type sécurisé. Pour des raisons historiques, il a été défini comme 0 sans transtypage, et le compilateur avertit par silence du nombre de transtypage pour pointer sur ce zéro spécial.
Pour l'instant, vous pouvez faire:
void* p = 0;
mais pas sans casting implicite:
void* p = 1234;
l'effet secondaire est qu'il peut être abusé en tant que valeurs numériques, comme une autre réponse mentionnée.
nullptr
améliorez cela en appliquant qu'il s'agit d'un pointeur, vous ne pouvez pas l'affecter à un entier. Étant donné que le comportement est modifié, un nouveau nom est créé pour la compatibilité descendante.
Notez également que nullptr
est géré par le compilateur, sa valeur réelle n'est pas exposée à l'utilisateur (comme zéro dans le cas de NULL
). Il est beaucoup plus facile d'avoir une valeur dépendante de l'architecture, par exemple 0xdeadbeef
, sans affecter la logique du code du programmeur.
Je vais démontrer un cas où la décision de définir nullptr comme un type différent aide à prévenir les bogues.
Considérez ces fonctions:
void foo(int);
void foo(char *);
int main()
{
foo(NULL); // oops
}
En C++ 98, le code ci-dessus appelle la fonction foo (int), car NULL est remplacé par 0, ce qui n'est probablement pas ce que vous vouliez.
Mais si vous appelez foo (nullptr) il appelle la bonne - foo (char *).
NULL
Vraisemblablement parce que le nouveau pointeur nul est un mot clé et que les mots clés ne peuvent pas être #defined
, donc l'appeler NULL
aurait rendu l'inclusion de tout en-tête C probablement mal formée.
NULL
doit être #defined
à nullptr
?Le comité des normes permet que NULL
soit #defined
à nullptr
, mais cela ne l'exige pas.
C++ 11 18.2 Types [support.types]/2: La macro
NULL
est une constante de pointeur nul C++ définie par l'implémentation dans la présente Norme internationale.C++ 11 4.10 Conversions de pointeur [conv.ptr]/1: A constante de pointeur nul est une expression constante intégrale ( 5.19) prvalue de type entier qui vaut zéro ou une valeur de type
std::nullptr_t
.
La compatibilité descendante n'est pas un problème ici, toute utilisation de NULL
qui suppose qu'il s'agit d'une forme de l'entier 0
n'est pas conforme à la norme. Les implémentations peuvent choisir de ne pas le faire pour tolérer ce type de comportement malveillant.
nullptr
est introduit pour la sécurité des types et pour la clarté (probablement pour arrêter l'initialisation des types sans pointeur à l'aide de NULL
).
Le NULL
(type int) n'est pas changé en nullptr
(type pointeur) pour éviter toute confusion et assurer la compatibilité descendante.
Ainsi, le train de pensée standard du comité est probablement lié à une transition en douceur de l'ancienne à la nouvelle notation sans provoquer d'ambiguïtés ni freiner un code déjà existant.