std::unique_ptr
| definiert in Header <memory>
|
||
template< class T, class Deleter = std::default_delete<T> > class unique_ptr; |
(1) | (seit C++11) |
template < class T, class Deleter > class unique_ptr<T[], Deleter>; |
(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_ptrdas 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_ptrwird zerstört, - oder dem verwaltenden
unique_ptrwird 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.
|
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ß Ts 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 Deleters, der typedef boost::offset_ptr pointer; oder einen anderen beliebten pointer definiert.
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_ptrs
|
Methoden
zerstört das verwaltete Objekt, wenn dieses vorhanden isterstellt 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) | |
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) |
Hilfsklassen
(C++11) |
Hash-Unterstützung für std::unique_ptr (class Template-Spezialisierung) |
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...
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) |