2013-01-07 10 views
41

Im C++ 11-Standard verstehe ich nicht den Grund, warum die Adresse von nullptr nicht erlaubt ist, während eine erlaubt, die Adresse ihrer eigenen std :: nullptr_t-Instanzen zu nehmen. Abgesehen von der Tatsache, dass nullptr ein reserviertes Schlüsselwort ist, gibt es eine bestimmte Begründung für diese Entscheidung?Warum kannst du nicht die Adresse von nullptr nehmen?

Ganz einfach, weil es mir Spaß macht, habe ich versucht, diese Einschränkung mit der folgenden Funktion zu umrunden:

decltype(nullptr)* func(const decltype(nullptr) &nref) noexcept 
{ 
    return const_cast<decltype(nullptr)*>(reinterpret_cast<const decltype(nullptr)*>(&nref)); 
} 

ich denn ohne sie reinterpret_cast auf den Parameter zu verwenden, hatte ich war immer die hysterischen Fehler:

error: invalid conversion from 'std::nullptr_t*' to 'std::nullptr_t*' [-fpermissive] 

Wenn ich diese Funktion durch die Übergabe nullptr direkt aufrufen, bekomme ich jedes Mal eine andere Adresse. Wird nullptr dynamisch eine Adresse just-in-time für Vergleiche zugewiesen? Oder (wahrscheinlich wahrscheinlicher) ist vielleicht der Compiler erzwingt eine temporäre Kopie des zugrunde liegenden Objekts?

Natürlich ist nichts davon wichtige Information, ich finde es nur interessant, warum diese bestimmte Einschränkung implementiert wurde (und warum ich das Verhalten sehe, das ich bin).

+22

'nullptr' ist ein Prvalue. Sie können die Adresse von denen nicht nehmen. +1 für die Fehlermeldung, obwohl. – chris

Antwort

78

Es ist das gleiche wie nicht in der Lage, die Adresse 5 zu nehmen, obwohl Sie die Adresse eines int nach dem Wert 5 nehmen können. Es spielt keine Rolle, dass es keinen alternativen Wert für eine nullptr_t haben soll.

Werte haben keine Adressen; Objekte tun.

ein temporäres Objekt erzeugt wird, wenn man einen solchen Wert zu einem const & Parameter übergeben werden oder auf andere Weise einen Wert auf eine konstante Referenz binden, wie beispielsweise durch static_cast< T const & >(…) oder einen benannten Referenz T const & foo = …; erklärt. Die Adresse, die Sie sehen, ist die des temporären.

+2

Danke! Ich habe tatsächlich ein wenig mehr gegraben und bin über [diese Antwort auf eine verwandte Frage] gestolpert (http://stackoverflow.com/questions/6664115/is-nullptr-not-a-special-keyword-and-an-object) -von-stdnullptr-t/6664283 # 6664283). Dann dämmerte mir, dass ** nullptr ** als Null-Zeiger-Literal gedacht ist, ja? Es macht Sinn, dass Sie die Adresse eines Literals nicht nehmen können. :) –

+18

Ja, 'nullptr' ist ein Schlüsselwort, das ein Literal darstellt. Genau wie 'true' und' false' (und du kannst auch '& true' nicht tun). – aschepler

+0

Yup! : D Ich glaube, als ich "null pointer _constant_" gelesen habe, habe ich es einfach als "_logical_ constant" anstatt als "_literal_ constant" gelesen. –

10

nullptr ist eine (literale) Konstante, und diese haben keine Speicheradresse, wie jede andere literale Konstante in Ihrem Code. Es ist ähnlich wie 0, aber der spezielle std::nullptr_t Typ anstelle von void*, um Probleme mit Überladung zu vermeiden (Zeiger vs. ganze Zahlen).

Aber wenn Sie Ihre eigene Variable mit dem Wert nullptr definieren, hat sie eine Speicheradresse, so dass Sie ihre Adresse nehmen können.

Das gleiche gilt für jede andere wörtliche Konstante (die in C++ fallen unter die Kategorie prvalue) eines anderen Typs, da wörtliche Konstanten sind nicht in Ihrem Programm gespeichert (nur als Teile von Ausdrücken, wo sie auftreten), deshalb macht es keinen Sinn über Adressen zu sprechen. Konstante Variablen haben jedoch Adressen, um auf den Unterschied hinzuweisen.

27

Wenn Sie nach einer Standard-Antwort sind, § 18.2/9 Ihre Beobachtungen ziemlich unverblümt ausdrückt:

Although nullptr’s address cannot be taken, the address of another nullptr_t object that is an lvalue can be taken.

Alternativ 2.14 §.7 sagt über nullptr:

The pointer literal is the keyword nullptr. It is a prvalue of type std::nullptr_t.

Also, was ein prvalue ist? § 3.10/1 Antworten, dass:

A prvalue (“pure” rvalue) is an rvalue that is not an xvalue. [ Example: The result of calling a function whose return type is not a reference is a prvalue. The value of a literal such as 12, 7.3e5, or true is also a prvalue. — end example ]

Hoffentlich versucht, die Adresse eines dieser Dinge im Beispiel zu nehmen mehr Sinn machen, warum Sie die Adresse nullptr nicht stattfinden können. Es ist Teil dieser Beispiele!

+0

Danke für die nützlichen Informationen! –

+2

Ah, ich wusste nicht, was ein Prvalue bis jetzt war, +1. –

+1

@SethCarnegie, ich mag ihre Definition. Manchmal, wenn ich durch den Standard gehe, um etwas vollständig zu definieren, erinnert es mich stark an Rekursion. – chris

4

Sowohl true als auch false sind Schlüsselwörter und als Literale haben sie einen Typ (bool). nullptr ist ein Zeigerliteral vom Typ std :: nullptr_t, und es ist ein prvalue (Sie können nicht die Adresse davon nehmen mit &), auch nullptr ist prvalue, so dass Sie ihre Adresse nicht nehmen können, literal Konstanten werden nicht in Ihrem Programm gespeichert.

Es macht keinen Sinn, Adresse zu haben.