669 Stimmen

Was genau ist nullptr?

Wir haben jetzt C++11 mit vielen neuen Funktionen. Eine interessante und verwirrende (zumindest für mich) ist die neue nullptr .

Nun, kein Grund mehr für das unangenehme Makro NULL .

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

Dennoch verstehe ich nicht, wie nullptr Werke. Zum Beispiel, Wikipedia-Artikel sagt:

C++11 korrigiert dies durch die Einführung einer neuen Stichwort als unterscheidbare Null-Zeiger-Konstante zu verwenden: nullptr. Sie ist von Typ nullptr_t der implizit konvertierbar und mit jedem Zeigertyp oder Zeiger-auf-Glied-Typ vergleichbar ist. Er ist nicht implizit konvertierbar oder vergleichbar mit ganzzahligen Typen, mit Ausnahme von bool.

Inwiefern ist es ein Schlüsselwort und eine Instanz eines Typs?

Haben Sie noch ein weiteres Beispiel (neben dem aus Wikipedia), in dem nullptr ist besser als die gute alte 0 ?

448voto

Johannes Schaub - litb Punkte 479831

Inwiefern ist es ein Schlüsselwort und eine Instanz eines Typs?

Das ist nicht verwunderlich. Beide true y false sind Schlüsselwörter und als Literale haben sie einen Typ ( bool ). nullptr es un Zeigerliteral vom Typ std::nullptr_t und es handelt sich um einen pr-Wert (Sie können die Adresse des Wertes nicht mit & ).

  • 4.10 über die Zeigerumwandlung besagt, dass ein pr-Wert vom Typ std::nullptr_t eine Null-Zeiger-Konstante ist und dass eine ganzzahlige Null-Zeiger-Konstante umgewandelt werden kann in std::nullptr_t . Die umgekehrte Richtung ist nicht erlaubt. Dies ermöglicht das Überladen einer Funktion sowohl für Zeiger als auch für ganze Zahlen und die Übergabe von nullptr um die Zeigerversion auszuwählen. Übergabe NULL o 0 würde verwirrenderweise die Option int Version.

  • Eine Besetzung von nullptr_t zu einem integralen Typ benötigt eine reinterpret_cast und hat die gleiche Semantik wie eine Besetzung von (void*)0 zu einem integralen Typ (Mapping-Implementierung definiert). A reinterpret_cast kann nicht konvertieren nullptr_t auf einen beliebigen Zeigertyp. Verlassen Sie sich, wenn möglich, auf die implizite Konvertierung oder verwenden Sie static_cast .

  • Der Standard verlangt, dass sizeof(nullptr_t) sein sizeof(void*) .

125voto

Gabriel Staples Punkte 20228

Warum nullptr in C++11? Was ist das? Warum ist NULL nicht ausreichend?

C++ Experte Alex Allain sagt es hier perfekt (meine Hervorhebung im Fettdruck):

...stellen Sie sich vor, Sie haben die folgenden zwei Funktionsdeklarationen:

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

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

Obwohl es so aussieht, als ob die zweite Funktion aufgerufen wird - schließlich übergeben Sie etwas, das ein Zeiger zu sein scheint -, ist es in Wirklichkeit die erste Funktion, die aufgerufen wird! Das Problem ist, dass die erste Version von func aufgerufen wird, weil NULL gleich 0 ist und 0 eine ganze Zahl ist. So etwas passiert zwar nicht immer, aber wenn es doch passiert, ist es extrem frustrierend und verwirrend. Wenn man die Details nicht kennt, könnte es durchaus wie ein Compilerfehler aussehen. Ein Sprachmerkmal, das wie ein Compilerfehler aussieht, ist, nun ja, nicht unbedingt erwünscht.

Nullptr eingeben. In C++11 ist nullptr ein neues Schlüsselwort, das zur Darstellung von NULL-Zeigern verwendet werden kann (und sollte!); mit anderen Worten, wo immer Sie vorher NULL geschrieben haben, sollten Sie stattdessen nullptr verwenden. Für Sie, den Programmierer, ist es nicht mehr klar (jeder weiß, was NULL bedeutet), aber für den Compiler ist es deutlicher die nicht mehr überall 0s sehen wird, die eine besondere Bedeutung haben, wenn sie als Zeiger verwendet werden.

Allain beendet seinen Artikel mit:

Unabhängig von all dem - die Faustregel für C++11 ist einfach, mit der nullptr wenn Sie sonst NULL in der Vergangenheit.

(Meine Worte):

Und schließlich sollten Sie nicht vergessen, dass nullptr ist ein Objekt - eine Klasse. Es kann überall verwendet werden NULL wurde zuvor verwendet, aber wenn Sie den Typ aus irgendeinem Grund benötigen, kann er mit decltype(nullptr) , oder direkt beschrieben als std::nullptr_t die einfach eine typedef von decltype(nullptr) wie hier gezeigt:

Definiert in der Kopfzeile <cstddef> :

Siehe:

  1. https://en.cppreference.com/w/cpp/types/nullptr_t
  2. et https://en.cppreference.com/w/cpp/header/cstddef

    namespace std { typedef decltype(nullptr) nullptr_t; // (since C++11) // OR (same thing, but using the C++ keyword using instead of the C and C++ // keyword typedef): using nullptr_t = decltype(nullptr); // (since C++11) } // namespace std

Referenzen:

  1. Cprogramming.de: Bessere Typen in C++11 - nullptr, enum-Klassen (stark typisierte Aufzählungen) und cstdint
  2. https://en.cppreference.com/w/cpp/language/decltype
  3. https://en.cppreference.com/w/cpp/types/nullptr_t
  4. https://en.cppreference.com/w/cpp/header/cstddef
  5. https://en.cppreference.com/w/cpp/keyword/using
  6. https://en.cppreference.com/w/cpp/keyword/typedef

64voto

nik Punkte 12812

Desde nullptr: Ein typsicherer und eindeutiger Null-Zeiger :

Das neue C++09-Schlüsselwort nullptr bezeichnet eine rvalue-Konstante, die als universelles Null-Zeiger-Literal dient und das fehlerbehaftete und schwach typisierte Literal 0 sowie das berüchtigte NULL-Makro ersetzt. nullptr macht damit Schluss mit mehr als 30 Jahren Peinlichkeit, Mehrdeutigkeit und Fehlern. In den folgenden Abschnitten wird die nullptr-Funktion vorgestellt und gezeigt, wie sie die Probleme von NULL und 0 beheben kann.

Andere Referenzen:

37voto

Motti Punkte 104854

Wenn Sie eine Funktion haben, die Zeiger auf mehr als einen Typ empfangen kann, rufen Sie sie mit NULL ist zweideutig. Die Art und Weise, wie dies jetzt umgangen wird, ist sehr hakelig, indem ein int akzeptiert wird und angenommen wird, dass es ein 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); }
};

Sur C++11 können Sie überladen mit nullptr_t so dass ptr<T> p(42); wäre eher ein Kompilierfehler als ein Laufzeitfehler assert .

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

11voto

user633658 Punkte 2255

nullptr kann nicht einem ganzzahligen Typ zugewiesen werden, wie z. B. einem int sondern nur einen Zeigertyp; entweder einen eingebauten Zeigertyp wie int *ptr oder einen intelligenten Zeiger wie std::shared_ptr<T>

Ich glaube, dass dies eine wichtige Unterscheidung ist, weil NULL kann immer noch sowohl einem ganzzahligen Typ als auch einem Zeiger zugewiesen werden als NULL ist ein Makro erweitert zu 0 der sowohl als Anfangswert für eine int als auch einen Zeiger.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X