Von hier aus adoptiert .
Die meisten Vorlagen in der C ++ - Standardbibliothek erfordern, dass sie mit vollständigen Typen instanziiert werden. Allerdings shared_ptr
und unique_ptr
sind teilweise Ausnahmen. Einige, aber nicht alle Mitglieder können mit unvollständigen Typen instanziiert werden. Die Motivation dafür ist, Redewendungen wie Pickel mit intelligenten Zeigern zu unterstützen, ohne undefiniertes Verhalten zu riskieren.
Undefiniertes Verhalten kann auftreten, wenn Sie einen unvollständigen Typ haben und ihn aufrufen delete
:
class A;
A* a = ...;
delete a;
Das obige ist ein gesetzlicher Code. Es wird kompiliert. Ihr Compiler gibt möglicherweise eine Warnung für den obigen Code wie den oben genannten aus. Wenn es ausgeführt wird, werden wahrscheinlich schlimme Dinge passieren. Wenn Sie sehr viel Glück haben, stürzt Ihr Programm ab. Ein wahrscheinlicheres Ergebnis ist jedoch, dass Ihr Programm stillschweigend Speicher verliert, da ~A()
es nicht aufgerufen wird.
Die Verwendung auto_ptr<A>
im obigen Beispiel hilft nicht. Sie erhalten immer noch das gleiche undefinierte Verhalten, als hätten Sie einen Rohzeiger verwendet.
Trotzdem ist es sehr nützlich, an bestimmten Stellen unvollständige Klassen zu verwenden! Dies ist wo shared_ptr
und unique_ptr
helfen. Wenn Sie einen dieser intelligenten Zeiger verwenden, können Sie mit einem unvollständigen Typ davonkommen, es sei denn, es ist ein vollständiger Typ erforderlich. Und am wichtigsten ist, dass Sie einen Fehler beim Kompilieren erhalten, wenn Sie versuchen, den Smart Pointer mit einem unvollständigen Typ zu diesem Zeitpunkt zu verwenden, wenn ein vollständiger Typ erforderlich ist.
Kein undefiniertes Verhalten mehr:
Wenn Ihr Code kompiliert wird, haben Sie überall einen vollständigen Typ verwendet, den Sie benötigen.
class A
{
class impl;
std::unique_ptr<impl> ptr_; // ok!
public:
A();
~A();
// ...
};
shared_ptr
und unique_ptr
erfordern einen vollständigen Typ an verschiedenen Stellen. Die Gründe sind unklar und haben mit einem dynamischen Löscher gegenüber einem statischen Löscher zu tun. Die genauen Gründe sind nicht wichtig. Tatsächlich ist es in den meisten Codes nicht wirklich wichtig, dass Sie genau wissen, wo ein vollständiger Typ erforderlich ist. Nur Code, und wenn Sie es falsch verstehen, wird der Compiler es Ihnen sagen.
Falls es für Sie jedoch hilfreich ist, finden Sie hier eine Tabelle, in der mehrere Mitglieder shared_ptr
und unique_ptr
in Bezug auf Vollständigkeitsanforderungen dokumentiert sind. Wenn das Mitglied einen vollständigen Typ benötigt, hat der Eintrag ein "C", andernfalls wird der Tabelleneintrag mit "I" gefüllt.
Complete type requirements for unique_ptr and shared_ptr
unique_ptr shared_ptr
+------------------------+---------------+---------------+
| P() | I | I |
| default constructor | | |
+------------------------+---------------+---------------+
| P(const P&) | N/A | I |
| copy constructor | | |
+------------------------+---------------+---------------+
| P(P&&) | I | I |
| move constructor | | |
+------------------------+---------------+---------------+
| ~P() | C | I |
| destructor | | |
+------------------------+---------------+---------------+
| P(A*) | I | C |
+------------------------+---------------+---------------+
| operator=(const P&) | N/A | I |
| copy assignment | | |
+------------------------+---------------+---------------+
| operator=(P&&) | C | I |
| move assignment | | |
+------------------------+---------------+---------------+
| reset() | C | I |
+------------------------+---------------+---------------+
| reset(A*) | C | C |
+------------------------+---------------+---------------+
Alle Operationen, die Zeigerkonvertierungen erfordern, erfordern vollständige Typen für unique_ptr
und shared_ptr
.
Der unique_ptr<A>{A*}
Konstruktor kann A
nur dann mit einer Unvollständigkeit davonkommen, wenn der Compiler keinen Aufruf an einrichten muss ~unique_ptr<A>()
. Wenn Sie zum Beispiel das unique_ptr
auf den Haufen legen , können Sie mit einem unvollständigen davonkommen A
. Weitere Details zu diesem Punkt finden Sie in der Antwort von BarryTheHatchet hier .
shared_ptr
/unique_ptr
". Die Tabelle am Ende sollte Ihre Frage beantworten.