Frage Löschen des Zeigers auf unvollständige Typ- und Smartpointer


Wenn Sie versuchen, ein auto_ptr mit einem Typ, der mit forward-declaration deklariert wurde:

class A;
...
std::auto_ptr<A> a;

der Destruktor von A wird nicht genannt (anscheinend, weil auto_ptr im Inneren deletes der zugrunde liegende Zeiger und der Destruktor für einen unvollständigen Typ können nicht aufgerufen werden).

Derselbe Code funktioniert jedoch einwandfrei, und der Destruktor wird beim Verwenden aufgerufen std::shared_ptr Anstatt von std::auto_ptr. Wie kann das erklärt werden?


19
2018-04-09 17:50


Ursprung


Antworten:


EIN shared_ptr kann mit einem unvollständigen Typ deklariert werden, ja. Der Typ muss nicht vollständig sein, bis Sie ihn initialisiert oder zurückgesetzt haben.

Wenn Sie initialisieren oder zurücksetzen a shared_ptr Um auf ein neues Objekt zu verweisen, wird ein "Deleter" erstellt, mit dem das Objekt zerstört werden kann. Betrachten Sie beispielsweise Folgendes:

// somewhere where A is incomplete:
std::shared_ptr<class A> p;

// define A
class A { /* ... */ };

p.reset(new A());

Wenn du anrufst reset, A ist abgeschlossen, weil Sie eine Instanz davon mithilfe von erstellen new. Das reset Funktion erstellt und speichert intern einen Deleter, mit dem das Objekt zerstört wird delete. weil A ist hier abgeschlossen, dass delete wird das Richtige tun.

Auf diese Weise shared_ptr erfordert das nicht A fertig sein, wenn die shared_ptr<A> wird erklärt; es erfordert nur das A ist abgeschlossen, wenn die shared_ptr Konstruktor, der einen rohen Zeiger verwendet, wird aufgerufen oder wenn Sie ihn aufrufen reset mit einem rohen Zeiger.

Beachten Sie, dass wenn A ist nicht wenn du eines dieser zwei Dinge machst, shared_ptr wird nicht das Richtige tun und das Verhalten ist undefiniert (das wird in erklärt die Dokumentation für boost::shared_ptr, das ist wahrscheinlich die beste Ressource für das Lernen zu benutzen shared_ptr richtig, egal welche Version von shared_ptr Sie verwenden (Boost, TR1, C ++ 0x usw.)).

Solange Sie jedoch immer den besten Usancen folgen shared_ptr- merklich, wenn Sie a immer initialisieren und zurücksetzen shared_ptr direkt mit einem Zeiger, der sich aus einem Aufruf von ergibt new- Sie müssen sich keine Sorgen darüber machen, dass Sie diese Regel verletzen.

Diese Funktionalität ist nicht kostenlos: shared_ptr muss einen Zeiger auf den Lösch-Funktor erzeugen und speichern; In der Regel geschieht dies, indem der Deleter als Teil des Blocks gespeichert wird, der die starke und schwache Referenzzählung speichert, oder indem ein Zeiger als Teil des Blocks auf den Deleter zeigt (da Sie einen eigenen Deleter bereitstellen können).

auto_ptr (und unique_ptr Auch ist es so konzipiert, dass es keinen Overhead hat: Operationen darauf sollen genauso effizient sein wie die Verwendung eines dummen Zeigers. So, auto_ptr hat diese Funktionalität nicht.


34
2018-04-09 17:59