std::unique_ptr
definiert in Header <memory>
|
||
template< class T, |
(1) | (seit C++11) |
template < class T, |
(2) | (seit C++11) |
std::unique_ptr
ist ein Smart-Pointer, der
- Alleineigentum eines Objekts über einen Zeiger besitzt
- und den Zeiger zerstört, sobald der
unique_ptr
das Ende seiner standardgemäßen Lebensdauer erreicht.
Ein Objekt wird zerstört unter Benutzung des objekteigenen Deleters, when eine der folgenden Operationen erfolgt:
- der verwaltende
unique_ptr
wird zerstört, - oder dem verwaltenden
unique_ptr
wird ein anderer Zeiger mittels operator= oder reset() zugewiesen.
Das Objekt wird mittels des, ggf. vom Benutzer übergebenen, Deleters durch Aufruf von get_deleter()(ptr) zerstört. Der voreingestellte Deleter verwendet den Operator delete, welches das Objekt zerstört und den Speicher freigibt.
Einem unique_ptr
kann auch kein Objekt zugewiesen sein.
In diesem Fall wird er als leer bezeichnet.
Es gibt zwei Versionen von std::unique_ptr
:
- verwaltet die Lebensdauer eines einzelnen Objekts, z.B. Objekte, die mit new allokiert worden sind.
- verwaltet die Lebensdauer eines Arrays mit einer dynamischer Größe, z.B. Arrays, die mit new[] allokiert worden sind.
Die Klasse erfüllt die Anforderungen von MoveConstructible
und MoveAssignable
, aber weder die von CopyConstructible
noch von CopyAssignable
.
Type requirements | ||
-Deleter muß ein FunctionObject , eine Referenz auf ein lokalisierbares FunctionObject oder eine Referenz auf eine lokalisierbare Funktion sein, die mit den Argument vom Typ unique_ptr<T, Deleter>::pointer aufgerufen werden kann.
|
Inhaltsverzeichnis |
[Bearbeiten] Anmerkungen
Nur nichtkonstante unique_ptr
können das Eigentum an dem verwalteten Objekt zu einem anderen unique_ptr
übertragen.
Ein konstanter std::unique_ptr kann keinen Eigentumsübertrag vornehmen, sondern begrenzen die Lebensdauer des verwalteten Objekts auf seine eigene Lebensdauer.
Zu den typischen Anwendungen von std::unique_ptr
gehören
- Sicherstellen der korrekten Freigabe von dynamischen Speicherressourcen unabhängig davon, ob die Funktion normal verlassen wurde oder eine Ausnahme ausgelöst worden ist.
- Übergabe der expliziten Eigentümerschaft von Objekten an aufzurufene Funktionen
- Übergabe der expliziten Eigentümerschaft von Objekten aus aufgerufenen Funktionen
- als Elemententyp von Containern, die die Move-Semantik unterstützen (z.B. std::vector), um Zeiger auf dynamisch erzeugte Objekte zu halten, um z.B. polymorphes Verhalten zu unterstützen.
Ein std::unique_ptr
kann mit einem unvollständigem Typ T
erzeugt werden, um die Benutzung im Rahmen des pImpl-Iidiom zu erlauben.
Falls der voreingestellte Delter benutzt wird, so muß T
vollständig definiert sein ab der Stelle im Quellkode, an der der Deleter aufgerufen wird.
Dieses geschieht im Destruktor, im Zuweisungsoperator mit Move-Semantik und beim Aufruf der Methode reset
.
(Im Gegensatz dazu kann std::shared_ptr nicht durch einen Zeiger auf einen unvollständigem Typ erzeugt werden, aber zerstört werden, obwohl ob T
unvollständig ist.
Falls T
eine Spezialisierung eines Klassentemplates ist, so erfordert die Benutzung von unique_ptr
als einen Operand, z.B. !p, daß T
s Parameter wegen ADL vollständig definiert sind.
Falls T
eine [[cpp/language/derived_class|abgeleitete Klasse] einer Basisklasse B
ist, dann ist std::unique_ptr<T> implizit umwandelbar nach std::unique_ptr<B>.
Der voreingestellte Deleter (operator delete for B
) des erzeugten std::unique_ptr<B> wird benutzt.
Dieses führt zu undefiniertem Verhalten, falls der Destruktor von B
nicht virtuell ist.
Im Gegensatz dazu verhält sich std::shared_ptr anders: std::shared_ptr<B> benutzt den operator delete des Typen T
und das verwaltete Objekt wird korrekt zerstört auch für den Fall, daß der Destruktor von B
nicht virtuell ist.
Anders als std::shared_ptr kann ein std::unique_ptr
jedes Objekt mittels eines benutzerdefinierten Typ verwalten, welches erfüllt.
Dieses erlaubt es, z.B. Objekte in shared memory zu verwalten durch zur Verfügung stellen eines Deleter
s, der typedef boost::offset_ptr pointer;
oder einen anderen beliebten pointer definiert.
[Bearbeiten] Klassentypen
muß erfüllt sein.Typ | Definition |
pointer | std::remove_reference<Deleter>::type::pointer falls dieser existiert, ansonsten T* .
|
element_type | T ; der Typ, der durch diesen unique_ptr verwaltet wird
|
deleter_type | Deleter ; Functor, Referenz auf eine Funktor bzw. eine Funktion zum Aufruf im Destruktor des unique_ptr s
|
[Bearbeiten] Methoden
zerstört das verwaltete Objekt, wenn dieses vorhanden ist erstellt einen neuen unique_ptr (öffentliche Elementfunktion) | |
weist den unique_ptr zu (öffentliche Elementfunktion) | |
modifizierend | |
liefert einen Zeiger auf das verwaltete Objekt und gibt ihn frei (öffentliche Elementfunktion) | |
ersetzt das verwaltete Objekt Original: replaces the managed object The text has been machine-translated via Google Translate. You can help to correct and verify the translation. Click here for instructions. (öffentliche Elementfunktion) | |
vertauscht die verwalteten Objekte Original: swaps the managed objects The text has been machine-translated via Google Translate. You can help to correct and verify the translation. Click here for instructions. (öffentliche Elementfunktion) | |
informierend | |
liefert einen Zeiger auf das verwaltete Objekt Original: returns a pointer to the managed object The text has been machine-translated via Google Translate. You can help to correct and verify the translation. Click here for instructions. (öffentliche Elementfunktion) | |
liefert die Funktion, die zur Zerstörung des verwalteten Objekt verwendet wird Original: returns the deleter that is used for destruction of the managed object The text has been machine-translated via Google Translate. You can help to correct and verify the translation. Click here for instructions. (öffentliche Elementfunktion) | |
prüft, ob verwalteten Objekt verknüpft ist Original: checks if there is associated managed object The text has been machine-translated via Google Translate. You can help to correct and verify the translation. Click here for instructions. (öffentliche Elementfunktion) | |
für objektverwaltende Zeiger | |
dereferenziert den Zeiger auf das verwaltete Objekt (öffentliche Elementfunktion) | |
für arrayverwaltende Zeiger | |
bietet indizierten Zugriff auf das verwaltete Array Original: provides indexed access to the managed array The text has been machine-translated via Google Translate. You can help to correct and verify the translation. Click here for instructions. (öffentliche Elementfunktion) |
[Bearbeiten] Assoziierte Funktionen
(C++14) (C++20) |
erzeugt einen intelligenten Zeiger mit explizitem Objektbesitz (Funktions-Template) |
vergleichen zweier unique_ptr bzw. eines unique_ptr mit einem nullptr (Funktions-Template) | |
(C++20) |
gibt den Wert des verwalteten Objektes an einen Ausgabestrom weiter (Funktions-Template) |
(C++11) |
Spezialisierung des std::swap-Algorithmus für Zeiger mit explizitem Besitz (Funktions-Template) |
[Bearbeiten] Hilfsklassen
(C++11) |
Hash-Unterstützung für std::unique_ptr (class Template-Spezialisierung) |
[Bearbeiten] Beispiele
#include <cassert> #include <cstdio> #include <fstream> #include <iostream> #include <memory> #include <stdexcept> // helper class for runtime polymorphism demo below struct B { virtual ~B() = default; virtual void bar() { std::cout << "B::bar\n"; } }; struct D : B { D() { std::cout << "D::D\n"; } ~D() { std::cout << "D::~D\n"; } void bar() override { std::cout << "D::bar\n"; } }; // a function consuming a unique_ptr can take it by value or by rvalue reference std::unique_ptr<D> pass_through(std::unique_ptr<D> p) { p->bar(); return p; } // helper function for the custom deleter demo below void close_file(std::FILE* fp) { std::fclose(fp); } // unique_ptr-based linked list demo struct List { struct Node { int data; std::unique_ptr<Node> next; }; std::unique_ptr<Node> head; ~List() { // destroy list nodes sequentially in a loop, the default destructor // would have invoked its `next`'s destructor recursively, which would // cause stack overflow for sufficiently large lists. while (head) head = std::move(head->next); } void push(int data) { head = std::unique_ptr<Node>(new Node{data, std::move(head)}); } }; int main() { std::cout << "1) Unique ownership semantics demo\n"; { // Create a (uniquely owned) resource std::unique_ptr<D> p = std::make_unique<D>(); // Transfer ownership to `pass_through`, // which in turn transfers ownership back through the return value std::unique_ptr<D> q = pass_through(std::move(p)); // `p` is now in a moved-from 'empty' state, equal to `nullptr` assert(!p); } std::cout << "\n" "2) Runtime polymorphism demo\n"; { // Create a derived resource and point to it via base type std::unique_ptr<B> p = std::make_unique<D>(); // Dynamic dispatch works as expected p->bar(); } std::cout << "\n" "3) Custom deleter demo\n"; std::ofstream("demo.txt") << 'x'; // prepare the file to read { using unique_file_t = std::unique_ptr<std::FILE, decltype(&close_file)>; unique_file_t fp(std::fopen("demo.txt", "r"), &close_file); if (fp) std::cout << char(std::fgetc(fp.get())) << '\n'; } // `close_file()` called here (if `fp` is not null) std::cout << "\n" "4) Custom lambda-expression deleter and exception safety demo\n"; try { std::unique_ptr<D, void(*)(D*)> p(new D, [](D* ptr) { std::cout << "destroying from a custom deleter...\n"; delete ptr; }); throw std::runtime_error(""); // `p` would leak here if it were instead a plain pointer } catch (const std::exception&) { std::cout << "Caught exception\n"; } std::cout << "\n" "5) Array form of unique_ptr demo\n"; { std::unique_ptr<D[]> p(new D[3]); } // `D::~D()` is called 3 times std::cout << "\n" "6) Linked list demo\n"; { List wall; for (int beer = 0; beer != 1'000'000; ++beer) wall.push(beer); std::cout << "1'000'000 bottles of beer on the wall...\n"; } // destroys all the beers }
Possible output:
1) Unique ownership semantics demo D::D D::bar D::~D 2) Runtime polymorphism demo D::D D::bar D::~D 3) Custom deleter demo x 4) Custom lambda-expression deleter and exception safety demo D::D destroying from a custom deleter... D::~D Caught exception 5) Array form of unique_ptr demo D::D D::D D::D D::~D D::~D D::~D 6) Linked list demo 1'000'000 bottles of beer on the wall...
[Bearbeiten] Referenzen
(C++11) |
intelligenter Zeiger, der geteilten Objektbesitz abbildet (Klassen-Template) |
(C++11) |
intelligenter Zeiger, der eine schwache, d.h. nicht blockierende, Referenz auf einen std::shared_ptr verwaltet (Klassen-Template) |