Question Qu'est-ce que nullptr?


Nous avons maintenant C ++ 11 avec de nombreuses nouvelles fonctionnalités. Une nouvelle intéressante et déroutante (du moins pour moi) est la nouvelle nullptr.

Eh bien, plus besoin de la macro méchante NULL.

int* x = nullptr;
myclass* obj = nullptr;

Pourtant, je ne comprends pas comment nullptr travaux. Par exemple, Article Wikipedia dit:

C ++ 11 corrige cela en introduisant une nouvelle mot-clé pour servir de constante de pointeur nul distingué: nullptr. C'est de tapez nullptr_t, qui est implicitement convertible et comparable à tout type de pointeur ou type de pointeur à membre. Il n'est pas implicitement convertible ou comparable aux types intégraux, sauf pour bool.

Comment est-ce un mot-clé et une instance d'un type?

Aussi, avez-vous un autre exemple (à côté de celui de Wikipedia) où nullptr est supérieur au bon vieux 0?


475
2017-08-15 16:47


origine


Réponses:


Comment est-ce un mot-clé et une instance d'un type?

Ce n'est pas surprenant. Tous les deux true et false sont des mots-clés et en tant que littéraux, ils ont un type ( bool ). nullptr est un littéral de pointeur de type std::nullptr_t, et c'est une valeur (vous ne pouvez pas prendre l'adresse en utilisant &).

  • 4.10 à propos de la conversion du pointeur dit qu'une prvalue de type std::nullptr_t est une constante de pointeur nul et qu'une constante de pointeur nul intégrale peut être convertie en std::nullptr_t. La direction opposée n'est pas autorisée. Cela permet de surcharger une fonction à la fois pour les pointeurs et les entiers et pour les nullptr pour sélectionner la version du pointeur. Qui passe NULL ou 0 serait déroutant de sélectionner le int version.

  • Une distribution de nullptr_t à un type intégral a besoin d'un reinterpret_cast, et a la même sémantique qu'une distribution de (void*)0 à un type intégral (implémentation de mappage définie). UNE reinterpret_cast ne peut pas convertir nullptr_t à n'importe quel type de pointeur. S'appuyer sur la conversion implicite si possible ou utiliser static_cast.

  • La norme exige que sizeof(nullptr_t) être sizeof(void*).


351
2017-08-15 17:06



De nullptr: un pointeur Null de type transparent:

Le nouveau mot clé nullptr C ++ 09 désigne une constante de valeur qui sert de littéral de pointeur null universel, remplaçant le littéral 0 mal défini et faiblement typé et la fameuse macro NULL. nullptr met ainsi fin à plus de 30 ans d’embarras, d’ambiguïté et de bugs. Les sections suivantes présentent la fonction nullptr et montrent comment elle peut remédier aux problèmes de NULL et de 0.

Autres références:


47
2017-08-15 17:02



Lorsque vous avez une fonction qui peut recevoir des pointeurs vers plusieurs types, l'appelez avec NULL c'est ambigu. La façon dont cela fonctionne maintenant est très piratée en acceptant un int et en supposant que c'est NULL.

template <class T>
class ptr {
    T* p_;
    public:
        ptr(T* p) : p_(p) {}

        template <class U>
        ptr(U* u) : p_(dynamic_cast<T*>(u)) { }

        // Without this ptr<T> p(NULL) would be ambiguous
        ptr(int null) : p_(NULL)  { assert(null == NULL); }
};

Dans C++11 vous seriez capable de surcharger nullptr_t pour que ptr<T> p(42); serait une erreur de compilation plutôt qu'une exécution assert.

ptr(std::nullptr_t) : p_(nullptr)  {  }

31
2017-08-16 06:46



Pourquoi nullptr en C ++ 11? Qu'Est-ce que c'est? Pourquoi NULL n'est-il pas suffisant?

Expert C ++ Alex Allain le dit parfaitement ici:

"... imaginez que vous avez les deux déclarations de fonction suivantes:

void func(int n); 
void func(char *s);

func( NULL ); // guess which function gets called?

Bien qu'il semble que la deuxième fonction sera appelée - vous passez, après tout, dans ce qui semble être un pointeur - c'est vraiment la première fonction qui sera appelée! Le problème est que, comme NULL vaut 0 et que 0 est un entier, la première version de func sera appelée à la place. C'est le genre de chose qui, oui, n'arrive pas tout le temps, mais quand cela arrive, c'est extrêmement frustrant et déroutant. Si vous ne connaissiez pas les détails de ce qui se passe, cela pourrait ressembler à un bogue de compilation. Une fonctionnalité de langage qui ressemble à un bogue de compilateur n'est pas ce que vous voulez.

Entrez nullptr. En C ++ 11, nullptr est un nouveau mot-clé qui peut (et devrait!) Être utilisé pour représenter les pointeurs NULL; En d'autres termes, où que vous écriviez NULL auparavant, vous devriez plutôt utiliser nullptr. Ce n'est pas plus clair pour vous, le programmeur, (tout le monde sait ce que NULL signifie), mais c'est plus explicite pour le compilateur, qui ne verra plus les 0 partout utilisés pour avoir une signification particulière quand ils sont utilisés comme pointeur. "


8
2018-03-07 06:18



nullptr ne peut pas être affecté à un integral type comme un int mais seulement un type pointer; soit un type de pointeur intégré tel que int *ptr ou un pointeur intelligent tel que std::shared_ptr<T>

Je crois que c'est une distinction importante parce que NULL peut toujours être affecté à un integral type et un pointer comme NULL est une macro étendue à 0 qui peut servir à la fois de valeur initiale pour un int ainsi qu'un pointer.


6
2018-01-29 13:12



Aussi, avez-vous un autre exemple (à côté de celui de Wikipedia) où nullptr est supérieur au bon vieux 0?

Oui. C'est aussi un exemple réel (simplifié) qui s'est produit dans notre code de production. Elle ne se démarquait que par le fait que gcc pouvait émettre un avertissement lors de la compilation croisée vers une plate-forme avec une largeur de registre différente (toujours pas sûr de savoir 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):

#include <iostream>

struct B {};

struct A
{
    operator B*() {return 0;}
    operator bool() {return true;}
};

int main()
{
    A a;
    B* pb = 0;
    typedef void* null_ptr_t;
    null_ptr_t null = 0;

    std::cout << "(a == pb): " << (a == pb) << std::endl;
    std::cout << "(a == 0): " << (a == 0) << std::endl; // no warning
    std::cout << "(a == NULL): " << (a == NULL) << std::endl; // warns sometimes
    std::cout << "(a == null): " << (a == null) << std::endl;
}

Il donne cette sortie:

(a == pb): 1
(a == 0): 0
(a == NULL): 0
(a == null): 1

4
2017-09-25 20:31



C'est un mot-clé car le standard le spécifie comme tel. ;-) Selon la dernière version publique (n2914)

2.14.7 Littéraux de pointeur [lex.nullptr]

pointer-literal:
nullptr

Le pointeur littéral est le mot-clé nullptr. C'est une valeur de type std::nullptr_t.

Il est utile car il ne convertit pas implicitement en une valeur intégrale.


3
2017-08-15 17:00



Eh bien, d'autres langues ont des mots réservés qui sont des instances de types. Python, par exemple:

>>> None = 5
  File "<stdin>", line 1
SyntaxError: assignment to None
>>> type(None)
<type 'NoneType'>

C'est en fait une comparaison assez proche parce que None est généralement utilisé pour quelque chose qui n'a pas été initialisé, mais en même temps des comparaisons telles que None == 0 sont faux.

D'autre part, en plaine C, NULL == 0 retournerait vrai IIRC parce que NULL est juste une macro renvoyant 0, qui est toujours une adresse invalide (AFAIK).


3
2017-08-15 16:52