Nous avons maintenant C ++ 11 avec de nombreuses nouvelles fonctionnalités. Un nouveau intéressant et déroutant (du moins pour moi) est le nouveau nullptr
.
Eh bien, plus besoin de la méchante macro NULL
.
int* x = nullptr;
myclass* obj = nullptr;
Pourtant, je ne comprends pas comment ça nullptr
marche. Par exemple, un article de Wikipedia dit:
C ++ 11 corrige cela en introduisant un nouveau mot clé pour servir de constante de pointeur nul distinct: nullptr. Il est de type nullptr_t , qui est implicitement convertible et comparable à tout type de pointeur ou de type pointeur sur membre. Il n'est pas implicitement convertible ou comparable aux types intégraux, à l'exception de bool.
Comment est-ce un mot-clé et une instance d'un type?
De plus, avez-vous un autre exemple (à côté de celui de Wikipedia) où nullptr
est supérieur au bon vieux 0
?
nullptr
est également utilisé pour représenter une référence nulle pour les descripteurs gérés en C ++ / CLI.nullptr_t
garanti d'avoir un seul membrenullptr
,? Donc, si une fonction est retournéenullptr_t
, le compilateur sait déjà quelle valeur sera renvoyée, quel que soit le corps de la fonction?std::nullptr_t
peut être instancié, mais toutes les instances seront identiques ànullptr
car le type est défini commetypedef decltype(nullptr) nullptr_t
. Je crois que la principale raison pour laquelle le type existe est pour que les fonctions puissent être surchargées spécifiquement pour intercepternullptr
, si nécessaire. Voir ici pour un exemple.Réponses:
Ce n'est pas surprenant. Les deux
true
etfalse
sont des mots clés et en tant que littéraux, ils ont un type (bool
).nullptr
est un pointeur littéral de typestd::nullptr_t
, et c'est une valeur (vous ne pouvez pas en prendre l'adresse en utilisant&
).4.10
À propos de la conversion de pointeur, une valeur de typestd::nullptr_t
est une constante de pointeur nulle et une constante de pointeur nul intégrale peut être convertie enstd::nullptr_t
. La direction opposée n'est pas autorisée. Cela permet de surcharger une fonction pour les pointeurs et les entiers, et de passernullptr
pour sélectionner la version du pointeur. PasserNULL
ou0
sélectionnerait laint
version avec confusion .Une conversion de
nullptr_t
vers un type intégral a besoin de areinterpret_cast
et a la même sémantique qu'une conversion de(void*)0
vers un type intégral (mise en œuvre de mappage définie). Areinterpret_cast
ne peut pas être convertinullptr_t
en n'importe quel type de pointeur. Comptez sur la conversion implicite si possible ou utilisezstatic_cast
.La norme exige que
sizeof(nullptr_t)
soitsizeof(void*)
.la source
cond ? nullptr : 0;
. Retiré de ma réponse.NULL
n'est même pas garanti d'être0
. Il peut l'être0L
, auquel cas un appel àvoid f(int); void f(char *);
sera ambigu.nullptr
favorisera toujours la version pointeur et n'appellera jamais celle-int
ci. Notez également qu'ilnullptr
est convertible enbool
(le projet dit que à4.12
).int
version. Maisf(0L)
est ambigu, carlong -> int
aussi bien que leslong -> void*
deux sont également coûteux. Donc, si NULL est0L
sur votre compilateur, un appelf(NULL)
sera ambigu étant donné ces deux fonctions. Pas sinullptr
bien sûr.(void*)0
en C ++. Mais il peut être défini comme n'importe quelle constante de pointeur nul arbitraire, que toute constante intégrale de valeur 0 etnullptr
remplit. Donc, certainement pas , mais le pouvez . (Vous avez oublié de me cingler btw ..)De nullptr: Un pointeur nul sûr et clair :
Autres références:
template
la source
Pourquoi nullptr en C ++ 11? Qu'Est-ce que c'est? Pourquoi NULL n'est-il pas suffisant?
L'expert C ++ Alex Allain le dit parfaitement ici (je souligne en gras):
Allain termine son article par:
(Mes mots):
Enfin, n'oubliez pas que
nullptr
c'est un objet - une classe. Il peut être utilisé n'importe où aNULL
été utilisé auparavant, mais si vous avez besoin de son type pour une raison quelconque, son type peut être extrait avecdecltype(nullptr)
, ou directement décrit commestd::nullptr_t
, qui est simplement untypedef
dedecltype(nullptr)
.Références:
la source
Lorsque vous avez une fonction qui peut recevoir des pointeurs vers plusieurs types, l'appeler avec
NULL
est ambigu. La façon dont cela fonctionne maintenant est très hacky en acceptant un int et en supposant que c'estNULL
.En
C++11
vous seriez en mesure de surcharge denullptr_t
sorte queptr<T> p(42);
serait une erreur de compilation plutôt qu'une exécutionassert
.la source
NULL
est défini comme0L
?nullptr
ne peut pas être affecté à un type intégral tel qu'unint
mais uniquement un type pointeur; soit un type de pointeur intégré tel queint *ptr
ou un pointeur intelligent tel questd::shared_ptr<T>
Je pense que c'est une distinction importante car elle
NULL
peut toujours être affectée à la fois à un type intégral et à un pointeur, tout commeNULL
une macro étendue0
qui peut servir à la fois de valeur initiale pourint
un pointeur et de pointeur.la source
NULL
n'est pas garanti d'être étendu à0
.Oui. C'est également un exemple (simplifié) du monde réel qui s'est produit dans notre code de production. Cela ne s'est démarqué que parce que gcc a pu émettre un avertissement lors de la compilation croisée vers une plate-forme avec une largeur de registre différente (toujours pas sûr exactement pourquoi uniquement lors de la compilation croisée de x86_64 à x86, avertit
warning: converting to non-pointer type 'int' from NULL
):Considérez ce code (C ++ 03):
Il donne cette sortie:
la source
Eh bien, d'autres langues ont des mots réservés qui sont des instances de types. Python, par exemple:
Il s'agit en fait d'une comparaison assez étroite, car elle
None
est généralement utilisée pour quelque chose qui n'a pas été initialisé, mais en même temps, des comparaisons telles queNone == 0
fausses.En revanche, en clair C,
NULL == 0
retournerait vrai IIRC carNULL
c'est juste une macro retournant 0, qui est toujours une adresse invalide (AFAIK).la source
NULL
est une macro qui se développe à un zéro, un zéro constant à un pointeur produit un pointeur nul. Un pointeur nul ne doit pas nécessairement être nul (mais souvent), zéro n'est pas toujours une adresse non valide, et un cast nul non constant en un pointeur n'a pas besoin d'être null, et un pointeur null cast en un entier ne doit pas être nul. J'espère avoir bien compris sans rien oublier. Une référence: c-faq.com/null/null2.htmlC'est un mot-clé car la norme le précisera comme tel. ;-) Selon le dernier projet public (n2914)
C'est utile car il ne se convertit pas implicitement en une valeur intégrale.
la source
Disons que vous avez une fonction (f) qui est surchargée pour prendre à la fois int et char *. Avant C ++ 11, si vous vouliez l'appeler avec un pointeur nul et que vous utilisiez NULL (c'est-à-dire la valeur 0), alors vous appelleriez celui surchargé pour int:
Ce n'est probablement pas ce que vous vouliez. C ++ 11 résout ce problème avec nullptr; Vous pouvez maintenant écrire ce qui suit:
la source
Permettez-moi d'abord de vous donner une mise en œuvre de peu sophistiquée
nullptr_t
nullptr
est un exemple subtil de l' idiome du résolveur de type de retour pour déduire automatiquement un pointeur nul du type correct en fonction du type de l'instance à laquelle il est affecté.nullptr
affectation à un pointeur entier, uneint
instanciation de type de la fonction de conversion modélisée est créée. Et il en va de même pour les pointeurs de méthode.nullptr
c'est un littéral entier avec la valeur zéro, vous ne pouvez pas utiliser son adresse que nous avons accomplie en supprimant & operator.Pourquoi avons-nous besoin
nullptr
en premier lieu?NULL
a un problème avec comme ci-dessous:1️⃣ Conversion implicite
2️⃣ Ambiguïté d'appel de fonction
3️⃣ Surcharge constructeur
String s((char*)0))
.la source
0 était la seule valeur entière pouvant être utilisée comme initialiseur sans transtypage pour les pointeurs: vous ne pouvez pas initialiser des pointeurs avec d'autres valeurs entières sans transtypage. Vous pouvez considérer 0 comme un singleton consexpr syntaxiquement similaire à un littéral entier. Il peut initier n'importe quel pointeur ou entier. Mais étonnamment, vous constaterez qu'il n'a pas de type distinct: il a été proposé d'être une véritable représentation constexpr singleton de valeur nulle pour initialiser les pointeurs. Il ne peut pas être utilisé pour initialiser directement des nombres entiers et élimine les ambiguïtés impliquées dans la définition en termes de 0. pourrait être défini comme une bibliothèque utilisant la syntaxe std mais semblait sémantiquement être un composant de base manquant. est désormais déconseillé en faveur de , sauf si une bibliothèque décide de le définir comme .
int
. Alors, comment se fait-il que 0 puisse initialiser des pointeurs et 1 non? Une réponse pratique était que nous avions besoin d'un moyen de définir la valeur nulle du pointeur et que la conversion implicite directe d'int
un pointeur est sujette aux erreurs. Ainsi, 0 est devenu une véritable bête bizarre bizarre de l'ère préhistorique.nullptr
NULL
nullptr
NULL
nullptr
nullptr
la source
Voici l'en-tête LLVM.
(beaucoup peut être découvert avec un rapide
grep -r /usr/include/*`
)Une chose qui saute aux yeux est la
*
surcharge de l'opérateur (retourner 0 est beaucoup plus convivial que segfaulting ...). Une autre chose est qu'il ne semble pas compatible avec le stockage d' une adresse à tous . Ce qui, comparé à la façon dont cela se fait en élinguant les vides * et en transmettant les résultats NULL aux pointeurs normaux en tant que valeurs sentinelles, réduirait évidemment le facteur "ne jamais oublier, ce pourrait être une bombe".la source
NULL n'a pas besoin d'être 0. Tant que vous utilisez toujours NULL et jamais 0, NULL peut être n'importe quelle valeur. En supposant que vous programmez un microcontrôleur von Neuman avec une mémoire plate, qui a ses vektors d'interruption à 0. Si NULL est 0 et que quelque chose écrit sur un pointeur NULL, le microcontrôleur se bloque. Si NULL est disons 1024 et à 1024 il y a une variable réservée, l'écriture ne la plantera pas, et vous pouvez détecter les affectations de pointeur NULL à l'intérieur du programme. C'est inutile sur les PC, mais pour les sondes spatiales, les équipements militaires ou médicaux, il est important de ne pas planter.
la source