23

Mit anderen Worten, wie überwacht die Implementierung die Zählung?Wie funktioniert die Referenzzählung eines Referenzzählers mit Smartpointern?

Gibt es ein kartenähnliches Objekt, auf das alle shared_ptr Instanzen zugreifen können, deren Schlüssel die Adresse des Zeigers ist und dessen Wert die Anzahl der Referenzen ist? Wenn ich eine shared_ptr implementieren muss, ist dies die erste Idee, die mir in den Sinn kommt.

Besteht die Möglichkeit eines Speicherlecks bei diesen Referenzzählen? Wenn ja, wie kann ich sie vermeiden?

Antwort

58

Ich habe zwei unterschiedliche nicht-intrusive Ansätze gesehen:

  1. der Smartpointer weist einen kleinen Speicherblock den Referenzzähler enthält. Jede Kopie des Smart-Pointers empfängt dann einen -Zeiger auf das tatsächliche Objekt und einen -Zeiger auf den Referenzzähler.
  2. Neben einem Objektzeiger enthält jedes Smartpointer einen vorherigen und nächsten Zeiger, wodurch eine doppelt verknüpfte Liste von Smart Pointer auf ein bestimmtes Objekt bildet. Die Referenzzahl ist implizit in der Liste. Wenn ein intelligenter Zeiger kopiert wird, fügt er sich zu der Liste hinzu. Nach der Zerstörung entfernt sich jeder Smartpointer von der Liste. Wenn es das letzte in der Liste ist, dann befreit es auch das referenzierte Objekt .

Wenn Sie here gehen und nach unten scrollen, gibt es ein ausgezeichnetes Diagramm, das diese Methoden viel deutlicher erklärt.

+0

Dies ist die korrekteste Antwort. –

+2

Der Ansatz mit verketteten Listen vermeidet die zusätzliche Zuweisung, ist aber ohne globalen Mutex sehr schwierig "Thread-sicher" zu machen. ("thread-safe" wie in "als thread-safe wie ein roher Zeiger") – curiousguy

+2

Auch wenn Sie 'make_shared' verwenden, kann die zusätzliche Zuweisung vermieden werden, indem das zugeordnete Objekt und der Instanzzähler in einem einzelnen Speicherblock abgelegt werden. – Ferruccio

2

Nr. Shared_ptr nur einen zusätzlichen Zeiger für Referenzzählung halten.

Wenn Sie eine Kopie des shared_ptr-Objekts erstellen, kopieren Sie den Zeiger mit der Anzahl der Referenzen, erhöhen ihn und kopieren den Zeiger auf das enthaltene Objekt.

2

Das Erstellen eines Speicherlecks mit Referenzzählern ist sehr einfach. Erstellen Sie einfach eine graphähnliche Struktur von Objekten, die einen Zyklus im Diagramm haben. Die Objekte im Zyklus verhindern, dass sie sich gegenseitig freigeben. Dies kann nicht automatisch gelöst werden. Wenn Sie beispielsweise eine Doppellink-Liste erstellen, müssen Sie darauf achten, nie mehr als ein Objekt gleichzeitig zu entfernen.

3

Jedes Smart-Pointer-Objekt enthält eine gemeinsame Referenzzählung - eine für jeden Rohzeiger.

Sie könnten einen Blick auf this Artikel werfen. Diese Implementierung speichert diese in einem separaten Objekt, das kopiert wird. Sie können auch einen Blick auf boost's documentation werfen oder einen Blick auf die Wikipedia article Smartpointer werfen.

+0

-1. Alle Smartpointer, die sich auf dasselbe Objekt beziehen, müssen * eine einzige Referenzzählung * teilen *. Das Objekt, das die Referenzzählung enthält, wird vom ersten intelligenten Zeigerobjekt zugewiesen, und * Zeiger auf es * (NICHT das Objekt selbst) werden kopiert, wenn der intelligente Zeiger kopiert wird. –

+0

Zustimmen bei j_random_hacker. Die Anzahl ist für jeden RAW-Zeiger eindeutig und wird von allen shared_ptr gemeinsam genutzt, die sich auf denselben RAW-Zeiger beziehen. Normalerweise wird es als ein separater Teil des Speichers zugewiesen, so dass smart_ptr zwei interne ptrs enthält, einen für die Referenzzählung und einen weiteren für den Zeiger selbst. –

+0

-1 für statische Variable. Sofern Sie nicht einen Smartzeiger mit Referenzzählung auf ein Singleton-Objekt implementieren, können Sie die Referenzzählung nicht mit Statik implementieren. –

2

Soweit ich mich erinnere, gab es das Problem der Verweis Zählzeiger in einem Kapitel von Effective C++ behandelt.

Im Prinzip haben Sie die Pointer-Klasse "light", die einen Zeiger auf eine Klasse enthält, die den Verweis enthält, der den Verweis inkrementieren/dekrementieren und das Pointer-Objekt zerstören kann. Diese Referenzzählklasse zeigt auf das Objekt, auf das Bezug genommen werden soll.

2

Viele Antworten beziehen sich auf die Art, wie die Referenzzählung gespeichert wird (sie wird in einem gemeinsamen Speicher für alle shared_ptr gespeichert, die denselben nativen Zeiger enthalten), aber die meisten entziehen sich dem Problem von Lecks.

Die einfachste Möglichkeit, Speicher mit Referenzzählern zu verlieren, ist das Erstellen von Zyklen. Als Beispiel wird garantiert, dass eine doppelt verkettete Liste, in der alle Zeiger shared_ptr mit mindestens zwei Elementen sind, nicht gelöscht wird. Selbst wenn externe Zeiger freigegeben werden, werden die internen Zeiger immer noch gezählt, und der Referenzzähler wird 0 nicht erreichen. Das ist zumindest mit der naivsten Implementierung.

Die einfachste Lösung für das Zyklusproblem ist das Mischen von shared_ptr (Referenzzähler) mit schwachen Zeigern, die den Eigentümer des Objekts nicht teilen.

Gemeinsam genutzte Zeiger teilen sich sowohl die Ressource (Zeiger) als auch die zusätzlichen Informationen zu reference_count. Wenn Sie schwache Zeiger verwenden, wird die Anzahl der Referenzen verdoppelt: Es gibt eine gemeinsame Referenz für den Zeiger und eine Referenz für den schwachen Zeiger. Die Ressource wird freigegeben, sobald der Zähler für gemeinsam genutzte Zeiger den Wert 0 erreicht, aber die Information referenz_zählstand bleibt bestehen, bis der letzte schwache Zeiger freigegeben wird.

In der doppelt verketteten Liste wird die externe Referenz in einem shared_ptr gehalten, während die internen Links nur schwach_ptr sind. Wenn keine externen Referenzen (shared_ptr) vorhanden sind, werden die Elemente der Liste freigegeben und die schwachen Referenzen gelöscht. Am Ende wurden alle schwachen Referenzen gelöscht und der letzte schwache Zeiger auf jede Ressource gibt die reference_count-Information frei.

Es ist weniger verwirrend als der obige Text scheint ... Ich werde es später noch einmal versuchen.

+2

Sie haben es später nicht noch einmal versucht. – xaxxon

Verwandte Themen