Programmiersprache C++: Mehr Prüfungen zur Compile-Zeit mit std::nullptr_t

vor 12 Stunden 1

Im heutigen Beitrag möchte ich dir die Vorteile eines oft unbekannten Datentyps zeigen: std::nullptr_t.

Portrait von Andreas Fertig

Andreas Fertig ist erfahrener C++-Trainer und Berater, der weltweit Präsenz- sowie Remote-Kurse anbietet. Er engagiert sich im C++-Standardisierungskomitee und spricht regelmäßig auf internationalen Konferenzen. Mit C++ Insights (https://cppinsights.io) hat er ein international anerkanntes Tool entwickelt, das C++-Programmierenden hilft, C++ noch besser zu verstehen.

Diesen Datentyp gibt es in der Sprache seit C++11, zusammen mit dem viel häufiger verwendeten nullptr. Während nullptr der Wert ist, bildet std::nullptr_t den Datentyp, der genau diesen Wert aufnehmen kann.

Wo ist std::nullptr_t hilfreich? Schauen wir uns std::string an. Ein std::string-Objekt aus einem nullptr zu erstellen, ist undefiniertes Verhalten. Dennoch kommt es vor. Deshalb haben heutzutage wahrscheinlich alle Standardbibliotheken eine Assertion, um dieses Vorgehen zu überprüfen.

Eine vereinfachte Version sieht wie folgt aus:

class string { // data members public: string(const char* str) { assert(nullptr != str); // ... } };

Man hat zwei Möglichkeiten, ein std::string-Objekt zu erstellen:

string berry{nullptr}; // #A const char* data{nullptr}; // #B string cherry{data}; // #C

In #A erstelle ich ein std::string-Objekt mit der Konstante nullptr und dem Datentyp std::nullptr_t. In #C ist der Fall hingegen etwas anders. Der const char* verweist auf einen nullptr, der von einer Laufzeitfunktion stammen könnte.

Um es klar zu sagen: Die assert-Prüfung im String-Konstruktor für #C wird nicht wegfallen, solange man die Nutzer davor schützen möchte, ein std::string-Objekt zur Laufzeit zu erstellen.

Dennoch kann man die Überprüfbarkeit zur Kompilierungszeit verbessern und so möglichst viele Fälle bereits zur Kompilierungszeit abfangen, wie in #A. Das Hinzufügen eines gelöschten Konstruktors für std::nullptr_t fängt alle Fälle von #A oben ab. Die string-Klasse sieht dann folgendermaßen aus:

class string { // data members public: string(const char* str) { assert(nullptr != str); // ... } string(std::nullptr_t) = delete("Construction from nullptr is not allowed"); };

Mithilfe von C++26 kann delete eine Meldung enthalten, die es ermöglicht, Hinweise zu hinterlassen, warum der Konstruktor gelöscht wurde.

In C++23 haben sowohl std::string als auch std::string_view einen gelöschten Konstruktor von std::nullptr_t, um diese Situationen zur Compile-Zeit abzufangen.

(rme)

Gesamten Artikel lesen