Wir haben jetzt C ++ 11 mit vielen neuen Funktionen. Eine interessante und verwirrende (zumindest für mich) ist die neue nullptr
.
Nun, das böse Makro ist nicht mehr nötig NULL
.
int* x = nullptr;
myclass* obj = nullptr;
Trotzdem verstehe ich nicht, wie es nullptr
funktioniert. Zum Beispiel sagt der Wikipedia-Artikel :
C ++ 11 korrigiert dies, indem ein neues Schlüsselwort eingeführt wird , das als definierte Nullzeigerkonstante dient: nullptr. Es ist vom Typ nullptr_t , der implizit konvertierbar und mit jedem Zeigertyp oder Zeiger-zu- Element -Typ vergleichbar ist. Es ist nicht implizit konvertierbar oder mit integralen Typen vergleichbar, außer für bool.
Wie ist es ein Schlüsselwort und eine Instanz eines Typs?
Haben Sie auch ein anderes Beispiel (neben dem Wikipedia-Beispiel), bei dem nullptr
es dem guten alten überlegen ist 0
?
nullptr
Wird auch verwendet, um eine Nullreferenz für verwaltete Handles in C ++ / CLI darzustellen.nullptr_t
garantiert nur ein Mitgliednullptr
? Wenn also eine Funktion zurückgegeben wirdnullptr_t
, weiß der Compiler bereits, welcher Wert zurückgegeben wird, unabhängig vom Funktionskörper?std::nullptr_t
kann instanziiert werden, aber alle Instanzen sind identisch mit,nullptr
da der Typ definiert ist alstypedef decltype(nullptr) nullptr_t
. Ich glaube, der Hauptgrund, warum der Typ existiert, ist, dass Funktionen bei Bedarf speziell zum Abfangen überladennullptr
werden können. Siehe hier für ein Beispiel.Antworten:
Das ist nicht überraschend. Beide
true
undfalse
sind Schlüsselwörter und als Literale haben sie einen Typ (bool
).nullptr
ist ein Zeiger wörtliche vom Typstd::nullptr_t
, und es ist ein prvalue (die Adresse der es nicht mit nehmen kann&
).4.10
Über die Zeigerkonvertierung heißt es, dass ein Wert vom Typstd::nullptr_t
eine Nullzeigerkonstante ist und dass eine integrale Nullzeigerkonstante in konvertiert werden kannstd::nullptr_t
. Die entgegengesetzte Richtung ist nicht erlaubt. Dies ermöglicht das Überladen einer Funktion sowohl für Zeiger als auch für Ganzzahlen und das Übergebennullptr
zur Auswahl der Zeigerversion. BestehenNULL
oder0
würde dieint
Version verwirrend auswählen .Eine Umwandlung
nullptr_t
in einen integralen Typ benötigt areinterpret_cast
und hat dieselbe Semantik wie eine Umwandlung(void*)0
in einen integralen Typ (Mapping-Implementierung definiert). Areinterpret_cast
kann nichtnullptr_t
in einen Zeigertyp konvertiert werden. Verlassen Sie sich nach Möglichkeit auf die implizite Konvertierung oder verwenden Sie diesestatic_cast
.Der Standard verlangt , dass
sizeof(nullptr_t)
seisizeof(void*)
.quelle
cond ? nullptr : 0;
. Aus meiner Antwort entfernt.NULL
nicht einmal garantiert ist0
. Es kann sein0L
, in welchem Fall ein Anruf anvoid f(int); void f(char *);
mehrdeutig ist.nullptr
wird immer die Zeigerversion bevorzugen und niemals dieint
eine aufrufen . Beachten Sie, dassnullptr
ist zu convertiblebool
(der Entwurf sagt , dass bei4.12
).int
Version aufrufen . Ist aberf(0L)
mehrdeutig, weillong -> int
sowohl als auchlong -> void*
beide gleich teuer sind. Wenn sich also NULL0L
auf Ihrem Compiler befindet, ist ein Aufruff(NULL)
angesichts dieser beiden Funktionen nicht eindeutig. Nicht sonullptr
natürlich.(void*)0
in C ++ definiert sein. Es kann aber als jede beliebige Nullzeigerkonstante definiert werden, die jede Integralkonstante mit dem Wert 0nullptr
erfüllt und erfüllt. Also definitiv nicht will, aber kann . (Sie haben vergessen , mich btw zu ping ..)Von nullptr: Ein typsicherer und eindeutiger Nullzeiger :
Weitere Referenzen:
template
quelle
Warum nullptr in C ++ 11? Was ist es? Warum reicht NULL nicht aus?
Der C ++ - Experte Alex Allain sagt es hier perfekt (meine Betonung ist fett gedruckt):
Allain beendet seinen Artikel mit:
(Meine Worte):
Vergessen Sie nicht, dass dies
nullptr
ein Objekt ist - eine Klasse. Es kann überallNULL
dort verwendet werden, wo es zuvor verwendet wurde, aber wenn Sie seinen Typ aus irgendeinem Grund benötigen, kann es mit extrahiertdecltype(nullptr)
oder direkt als beschrieben werdenstd::nullptr_t
, was einfach eintypedef
von istdecltype(nullptr)
.Verweise:
quelle
Wenn Sie eine Funktion haben, die Zeiger auf mehr als einen Typ empfangen kann, ist der Aufruf mit nicht
NULL
eindeutig. Die Art und Weise, wie dies jetzt umgangen wird, ist sehr hackig, wenn man ein int akzeptiert und davon ausgeht, dass es istNULL
.In
C++11
könnten Sie überladen,nullptr_t
so dassptr<T> p(42);
dies eher ein Kompilierungsfehler als eine Laufzeit wäreassert
.quelle
NULL
definiert ist als0L
?nullptr
kann keinem integralen Typ wie einem,int
sondern nur einem Zeigertyp zugewiesen werden ; entweder ein eingebauter Zeigertyp wieint *ptr
oder ein intelligenter Zeiger wiestd::shared_ptr<T>
Ich glaube, dies ist eine wichtige Unterscheidung, da
NULL
immer noch sowohl ein integraler Typ als auch ein Zeiger zugewiesen werden können, ebenso wieNULL
ein erweitertes Makro,0
das sowohl als Anfangswert für einenint
als auch als Zeiger dienen kann.quelle
NULL
wird nicht garantiert erweitert0
.Ja. Es ist auch ein (vereinfachtes) Beispiel aus der Praxis, das in unserem Produktionscode vorkommt. Es fiel nur auf, weil gcc beim Crosscompilieren auf eine Plattform mit unterschiedlicher Registerbreite eine Warnung ausgeben konnte (immer noch nicht sicher, warum, nur beim Crosscompilieren von x86_64 auf x86, warnt
warning: converting to non-pointer type 'int' from NULL
):Betrachten Sie diesen Code (C ++ 03):
Es ergibt diese Ausgabe:
quelle
Nun, andere Sprachen haben reservierte Wörter, die Instanzen von Typen sind. Python zum Beispiel:
Dies ist eigentlich ein ziemlich enger Vergleich, da er
None
normalerweise für etwas verwendet wird, das nicht initialisiert wurde, aber gleichzeitig Vergleiche wieNone == 0
falsch sind.Andererseits würde in einfachem C
NULL == 0
wahres IIRC zurückgeben, daNULL
es sich nur um ein Makro handelt, das 0 zurückgibt , was immer eine ungültige Adresse (AFAIK) ist.quelle
NULL
ist ein Makro, das auf eine Null erweitert wird. Eine konstante Null, die in einen Zeiger umgewandelt wird, erzeugt einen Nullzeiger. Ein Nullzeiger muss nicht Null sein (ist es aber oft), Null ist nicht immer eine ungültige Adresse, und eine nicht konstante Null, die in einen Zeiger umgewandelt wird, muss nicht Null sein, und ein Nullzeiger, der in einen Zeiger umgewandelt wird Ganzzahl muss nicht Null sein. Ich hoffe, ich habe das in Ordnung gebracht, ohne etwas zu vergessen. Eine Referenz: c-faq.com/null/null2.htmlEs ist ein Schlüsselwort, da der Standard es als solches spezifiziert. ;-) Nach dem neuesten öffentlichen Entwurf (n2914)
Dies ist nützlich, da es nicht implizit in einen ganzzahligen Wert konvertiert wird.
quelle
Angenommen, Sie haben eine Funktion (f), die überladen ist, um sowohl int als auch char * zu übernehmen. Wenn Sie es vor C ++ 11 mit einem Nullzeiger aufrufen wollten und NULL (dh den Wert 0) verwendeten, würden Sie das für int überladene aufrufen:
Dies ist wahrscheinlich nicht das, was Sie wollten. C ++ 11 löst dies mit nullptr; Jetzt können Sie Folgendes schreiben:
quelle
Lassen Sie mich zunächst eine Implementierung von ungekünstelt geben
nullptr_t
nullptr
ist ein subtiles Beispiel für die Rückgabetyp-Resolver-Sprache, mit der automatisch ein Nullzeiger des richtigen Typs abgeleitet wird, abhängig vom Typ der Instanz, der er zugewiesen wird.nullptr
Zuweisen zu einem Ganzzahlzeiger eineint
Typinstanziierung der Vorlagenkonvertierungsfunktion erstellt. Gleiches gilt auch für Methodenzeiger.nullptr
es sich um ein ganzzahliges Literal mit dem Wert Null handelt, können Sie seine Adresse nicht verwenden, was wir durch Löschen von & operator erreicht haben.Warum brauchen wir überhaupt
nullptr
?NULL
hat ein Problem damit wie folgt:1️⃣ Implizite Konvertierung
2️⃣ Mehrdeutigkeit von Funktionsaufrufen
3️⃣ Konstruktorüberlastung
String s((char*)0))
.quelle
0 war früher der einzige ganzzahlige Wert, der als umwandlungsfreier Initialisierer für Zeiger verwendet werden konnte: Sie können Zeiger ohne Umwandlung nicht mit anderen ganzzahligen Werten initialisieren. Sie können 0 als einen Consexpr-Singleton betrachten, der syntaktisch einem ganzzahligen Literal ähnlich ist. Es kann einen beliebigen Zeiger oder eine Ganzzahl initiieren. Aber überraschenderweise werden Sie feststellen, dass es keinen bestimmten Typ hat: Es ist ein
int
. Wie kommt es also, dass 0 Zeiger initialisieren kann und 1 nicht? Eine praktische Antwort war, dass wir ein Mittel zum Definieren des Zeiger-Nullwerts benötigen und die direkte implizite Konvertierungint
in einen Zeiger fehleranfällig ist. So wurde 0 ein echtes Freak-Weirdo-Biest aus der prähistorischen Zeit.nullptr
Es wurde vorgeschlagen, eine echte Singleton-Constexpr-Darstellung des Nullwerts zu sein, um Zeiger zu initialisieren. Es kann nicht verwendet werden, um Ganzzahlen direkt zu initialisieren, und beseitigt Unklarheiten, die mit der DefinitionNULL
in Bezug auf 0 verbunden sind. Esnullptr
könnte als Bibliothek mit Standardsyntax definiert werden, wird jedoch semantisch als fehlende Kernkomponente angesehen.NULL
wird jetzt zugunsten von abgelehntnullptr
, es sei denn, eine Bibliothek beschließt, es als zu definierennullptr
.quelle
Hier ist der LLVM-Header.
(viel kann mit einem schnellen aufgedeckt werden
grep -r /usr/include/*`
)Eine Sache, die herausspringt, ist die
*
Überlastung des Operators (die Rückgabe von 0 ist viel freundlicher als Segfaulting ...). Eine andere Sache ist es nicht kompatibel sieht mit Speichern einer Adresse überhaupt . Was im Vergleich dazu, wie es geht, Leere * zu schleudern und NULL-Ergebnisse als Sentinel-Werte an normale Zeiger zu übergeben, offensichtlich den Faktor "Niemals vergessen, es könnte eine Bombe sein" reduzieren würde.quelle
NULL muss nicht 0 sein. Solange Sie immer NULL und niemals 0 verwenden, kann NULL ein beliebiger Wert sein. Angenommen, Sie programmieren einen von Neuman-Mikrocontroller mit flachem Speicher, dessen Interrupt vektoren bei 0 liegt. Wenn NULL 0 ist und etwas an einem NULL-Zeiger schreibt, stürzt der Mikrocontroller ab. Wenn NULL beispielsweise 1024 ist und bei 1024 eine reservierte Variable vorhanden ist, stürzt der Schreibvorgang nicht ab, und Sie können NULL-Zeigerzuweisungen im Programm erkennen. Dies ist auf PCs sinnlos, aber für Raumsonden, militärische oder medizinische Geräte ist es wichtig, nicht abzustürzen.
quelle