CPP2019SSF06

Aus Verteilte Systeme - Wiki
Zur Navigation springen Zur Suche springen

Feature: nullptr

  • Eingeführt in: C++11

Syntax

auto nullp = nullptr;     // type std::nullptr_t

Use Cases

In folgenden Fällen kann man das keyword nullptr verwenden:

  • Pointer als ungültig machen
  • Pointer leer initialisieren
  • bei Smart Pointern: Besitz eines Objektes aufgeben oder Objekt zerstören
  • darauf reagieren wenn in Funktion ein ungültiger Pointer übergeben wird

In den Codebeispielen werden diese Use Cases verdeutlicht.

Motivation für die Einführung

Schon in C hat man einen Mechanismus gesucht, mit dem man einen Pointer entweder als ungültig markieren will oder ohne Inhalt initialisieren möchte. Daraus entstand das Makro NULL. In C war dieses Makro vom Typ void*. Da in C++ kein Cast von einem void* zu einem Pointer eines anderen Typs möglich ist, wurde das Makro NULL einfach als 0 definiert.

#define NULL 0

Zusätzlich möchte man eventuell darauf reagieren wenn ein ungültiger bzw. leerer Pointer in einer Funktion übergeben wird. Wie man im folgenden Beispiel sehen kann, war dies bisher nicht immer möglich und konnte unter Umständen zu uneindeutigen aufrufen führen.

Vorherige Lösungsansätze

Das Makro NULL, das man auch aus C kennt ist in C++ intern einfach eine 0 ist. Die 0 ist ebenso eine Speicheradresse, die in der Regel für System-Dienste reserviert ist. Somit ist ein Pointer mit dieser Adresse als ungültig bzw. uninitialisiert markiert.

Da das Makro NULL jedoch eine 0 ist kann es implizit in ein int konvertiert werden, was zu mehrdeutigen Methodenaufrufen führen kann. Der folgende Code ist zwar kein alltäglicher Fall, zeigt aber welche Gefahren durch das Benutzen von NULL entstehen können und wie so ein mehrdeutiger Aufruf aussehen kann.

void func(int *p);
void func(int n); 

func(NULL);

Man könnte hier erwarten, dass die erste Funktion aufgerufen wird, da diese einen Pointer des Typs int (*int) erwartet und man einen Pointer übergibt während die zweite einen int erwartet. Jedoch passiert es ganz anders herum. Die Funktion 2 wird ausgeführt, denn das Makro NULL wird hier implizit in einen int konvertiert und zwar mit dem wert 0. Mit der Einführung des keywords nullptr wurde dies umgangen, denn es kann nicht mehr als 0 interpretiert werden.

Interne Repräsentation

Seit C++ 11 existiert das keyword nullptr. Es ist vom Typ std::nullptr_t.

Auch das Makro NULL hat sich mit der Einführung geändert.

#define NULL 0
// Seit C++ 11
#define NULL nullptr

Abhängig vom System hat es entweder den Wert 0 oder nullptr. Auch deswegen sollte man in Zukunft wann immer man vorher NULL verwendet hat, nullptr benutzen.

Code-Beispiele

Leere Initialisierung

Im folgenden Beispiel wird nullptr dafür verwendet dass ein Pointer für ein Objekt leer initialisiert wird, da es erst im späteren Verlauf einen Inhalt bekommt

auto factory = new CarFactory();

Car *car = nullptr;

/*
 * ...
 * factory bekommt Autoteile etc.
 * ...
 */

car = factory->createCar();

Auch die Verwendung von Smart-Pointern stellt kein Problem dar.

unique_ptr<Car> car(nullptr);

/*
 * ...
 */

car.reset(factory->createCar());


Pointer uLink-Textngültig markieren

Im folgenden Beispiel sieht man wie man nullptr dafür verwenden kann einen Pointer auf ein Objekt ungültig zu machen. Bei Smart-Pointern wie beispielsweise dem unique_ptr hat das zusätzlich den Effekt dass das Objekt damit zerstört wird.

unique_ptr<Car> car(factory->createCar());

/*
 * ...
 * car crashes or whatever
 * ...
 */

car = nullptr;

Bei dem Beispiel wird auch sichtbar, wie man es sich zu nutze machen kann, dass man eine Funktion mit dem Typ nullptr_t überladen kann. Denn nichts anderes passiert bei dem unique_ptr. Dort ist der =-Operator mit dem Typ nullptr_t überladen, dass das zerstören des Objektes damit umgesetzt werden kann. Intern sieht das so aus:

unique_ptr& operator=( nullptr_t )

Präsentation

Präsentation