Skip to content

Latest commit

 

History

History
152 lines (99 loc) · 3.7 KB

File metadata and controls

152 lines (99 loc) · 3.7 KB

Weak Pointer: Klasse std::weak_ptr

Zurück


Quellcode


Inhalt


„It's about ownership”

Exklusiver Besitz: std::unique_ptr<T>
Geteilter Besitz: std::shared_ptr<T>

Temporärer Besitz: std::weak_ptr<T>


Funktionsweise Klasse std::weak_ptr

Die Funktionsweise der Klasse std::weak_ptr wird an zwei Beispielen aufgezeigt.

Das erste Beispiel erläutert vor allem den Zusammenhang zwischen den beiden Klassen std::weak_ptr und std::shared_ptr.

Ein zweites Beispiel demonstriert die Probleme mehrere Objekte, die sich durch std::shared_ptr-Objekte gegenseitig referenzieren.


Control Block

Der bei std::shared_ptr-Objekten vorhandene Control Block bezieht auch std::weak_ptr-Objekte mit ein:

Abbildung 1: std::weak_ptr-Objekt und Control-Block.


Zyklische Referenzen

Interessant ist der Weak-Pointer bei zyklischen Referenzen:

Abbildung 2: Zyklische Referenzen.

Beachten Sie die Ausgabe des zweiten Code-Snippets: Hier haben wir es mit einer zyklischen Referenz von Shared-Pointern zu tun. Im einen Fall werden alle beteiligten Zeiger freigegeben, im anderen auf Grund der zyklischen Referenzen nicht.

c'tor ParentNode
c'tor RightNode
c'tor LeftNode

d'tor LeftNode

oder

c'tor ParentNode
c'tor RightNode
c'tor LeftNode

d'tor LeftNode
d'tor RightNode
d'tor ParentNode

Betrachtung der Referenzzähler im Detail

Wir sind dem Problem von std::shared_ptr-Objekten und zyklischen Referenzen auf die Spur gekommen. Möglicherweise ist es aber immer noch nicht ganz genau verständlich geworden, warum es mit der Freigabe allokierten Speichers in diesem Fall nicht funktioniert.

Zu diesem Zweck haben wir das letzte Beispiel auf die wesentlichen Bestandteile komprimiert:

01: struct X;
02: struct Y;
03: 
04: struct X
05: {
06:     std::shared_ptr<Y> m_spY{};
07: };
08: 
09: struct Y
10: {
11:     std::shared_ptr<X> m_spX{};
12: };
13: 
14: void test() {
15: 
16:     std::shared_ptr<X> sp1{ std::make_shared<X>() };
17:     std::shared_ptr<Y> sp2{ std::make_shared<Y>() };
18: 
19:     sp1->m_spY = sp2;
20:     sp2->m_spX = sp1;
21: }

Eine Studie von mehreren Bildern verdeutlicht nun, warum es bei einem Zyklus mit der Freigabe des allokierten Speichers nicht klappen kann – und beim Beseitigen des Zyklusses doch:

Abbildung 3: Ein erstes, dynamisch allokiertes Objekt wird angelegt.

Abbildung 4: Ein zweites, dynamisch allokiertes Objekt wird angelegt.

Abbildung 5: Wertzuweisung std::shared_ptr-Variable.

Abbildung 6: Zweite Wertzuweisung std::shared_ptr-Variable.

Wir erkennen nun in Abbildung 5, dass ein Zyklus vorhanden ist!

Abbildung 7: Die auf dem Stack vorhandenen std::shared_ptr-Variablen werden entfernt: Es verbleibt ein Zyklus auf dem Heap!

Ein genaues Studium dieser Abbildungen sollte verdeutlichen, warum Zyklen bei dynamisch verzeigerten Objekten mit einem Referenzzähler-Mechanismus nicht korrekt verwaltet werden können.


Zurück