boost::weak_ptr...
-
Kannst du das mal genauer Erklären, @Dravere?
"Also Objekt A hält shared_ptr zu B und B hält shared_ptr zu A."
Wie sieht das codemäßig aus?
THX!
-
Verstand schrieb:
Kannst du das mal genauer Erklären, @Dravere?
"Also Objekt A hält shared_ptr zu B und B hält shared_ptr zu A."
Wie sieht das codemäßig aus?
THX!struct B; struct A { //... boost::shared_ptr<B> myBPtr; //... }; struct B { //... boost::shared_ptr<A> myAPtr; //... };
-
Tachyon schrieb:
theta schrieb:
Und auch um dangling pointers zu verhindern.
SimonWie das? Man muss doch extra Aufwand mit den Locks betreiben, um hängende Zeiger zu verhindern. Ich wage sogar zu behaupten, dass die Gefahr von hängenden Zeigern bei der Benutzung von
weak_ptrsteigt.http://www.boost.org/doc/libs/1_38_0/libs/smart_ptr/weak_ptr.htm
Nein, nur die Methode um vom weak_ptr wieder an den pointer via shared_ptr zu kommen heisst lock().
Simon
-
theta schrieb:
Tachyon schrieb:
theta schrieb:
Und auch um dangling pointers zu verhindern.
SimonWie das? Man muss doch extra Aufwand mit den Locks betreiben, um hängende Zeiger zu verhindern. Ich wage sogar zu behaupten, dass die Gefahr von hängenden Zeigern bei der Benutzung von
weak_ptrsteigt.http://www.boost.org/doc/libs/1_38_0/libs/smart_ptr/weak_ptr.htm
Nein, nur die Methode um vom weak_ptr wieder an den pointer via shared_ptr zu kommen heisst lock().
Simon
Und wo steht da, dass es hängende Zeiger verhindert? Man kann einen
weak_ptreh nur mitshared_ptr-Objekten erzeugen. Und der generierendechared_ptrminimiert ja bereits die Wahrscheinlichkeit für hängende Zeiger. Und wenn ich das richtig sehe, kann man die verwalteten Objekte auch nicht direkt über einenweak_ptrreferenzieren. Man muss also den Umweg über einenshared_ptrmitlock()gehen.
-
Und wo steht da, dass es hängende Zeiger verhindert?
Suche halt mal nach "dangling" oder ähnlich auf der Seite...
Und ja, man muss von weak_ptr zuerst eine shared_ptr erzeugen.
Simon
Edit:
lock() ist die eine Möglichkeit, den shared_ptr ctor ist die andere.
-
theta schrieb:
Suche halt mal nach "dangling" oder ähnlich auf der Seite..
Wie gesagt, da steht nur, dass man sich leicht hängende Zeiger einfängt, wenn man nicht aufpasst...
-
Tachyon schrieb:
Wie gesagt, da steht nur, dass man sich leicht hängende Zeiger einfängt, wenn man nicht aufpasst...
weak_ptr verhindert auch nicht, das kein Zielobjekt existiert, bekommt aber im Gegensatz zu einem Zeiger davon mit wenn dies eintritt. Stell dir weak_ptr einfach als einen Zeiger vor, der automatisch auf null gesetzt wird, wenn kein zugehöriger shared_ptr mehr existiert.
-
asc schrieb:
Tachyon schrieb:
Wie gesagt, da steht nur, dass man sich leicht hängende Zeiger einfängt, wenn man nicht aufpasst...
weak_ptr verhindert auch nicht, das kein Zielobjekt existiert, bekommt aber im Gegensatz zu einem Zeiger davon mit wenn dies eintritt. Stell dir weak_ptr einfach als einen Zeiger vor, der automatisch auf null gesetzt wird, wenn kein zugehöriger shared_ptr mehr existiert.
Das ist schon klar. Nur hat
weak_ptrnur in Verbindung mitshared_ptrSinn (es geht nichtmal ohne). Und auch dabei braucht man ihn nur, um zirkulare Referenzen zu entblocken.
Der Sinn ist es daher sicher nicht, hängende Zeiger zu vermeiden. Es geht soch wohl eher darum, zirkulare Referenzen aufzulösen, ohne dasshared_ptr-Konzept zu aufzuweichen.
Die Frage war:Tachyon schrieb:
Was genau ist der Sinn und Zweck von boost::weak_ptr?
Die Antwort...
theta schrieb:
Und auch um dangling pointers zu verhindern.
...ist so einfach falsch.
PS: Mit ist inzwischen zwar klar, dass theta das im Bezug auf den eigentlichen Verwendungszweck meint, aber als er die Antwort gab, war es das noch nicht.
-
Verstand schrieb:
Kannst du das mal genauer Erklären, @Dravere?
"Also Objekt A hält shared_ptr zu B und B hält shared_ptr zu A."
Wie sieht das codemäßig aus?
THX!Ich gebe dazu gerne mal ein Beispiel, welches sogar kompilierbar ist, gegenüber dem Beispiel von Tachyon. Damit sollte es jedem klar werden

#include <boost/shared_ptr.hpp> #include <iostream> struct MyClassA; struct MyClassB; // Nur wegen der Schreibfaulheit :) typedef boost::shared_ptr<MyClassA> MyClassAPtr; typedef boost::shared_ptr<MyClassB> MyClassBPtr; struct MyClassA { MyClassBPtr bPtr; ~MyClassA() { std::cout << "A destroyed" << std::endl; } }; struct MyClassB { MyClassAPtr aPtr; ~MyClassB() { std::cout << "B destroyed" << std::endl; } }; void foo() { MyClassAPtr objA(new MyClassA()); MyClassBPtr objB(new MyClassB()); objA->bPtr = objB; objB->aPtr = objA; } int main() { foo(); // Speicherleck entstanden. // Kein Zeiger mehr auf die Objekte vorhanden, // aber beide die shared_ptr erreichen bei der // Referenzzählung keinen Wert von 0. Die // Objekte werden nicht freigegeben. return 0; }Du kannst das Speicherleck auch dadurch sehen, dass die Destruktoren nicht aufgerufen werden.
Einboost::weak_ptrkann diese Abhängigkeit nun in eine Richtung verringern, da einboost::weak_ptrbei der Referenzzählung nicht gilt. Eines der beiden Objekt erreicht dann die Anzahl Referenzen von 0. Löscht sich dadurch und verringert die Referenzzählung des anderen Objektes, welches dann auch gelöscht wird.
Also einfach die folgende Zeile abändern (in der Struktur MyClassB):MyClassAPtr aPtr;zu
boost::weak_ptr<MyClassA> aPtr;(
#include <boost/weak_ptr.hpp>nicht vergessen)Wenn du nun das Programm ausführst, dann wird alles korrekt gelöscht.
Grüssli
-
Also ich muß da mal nachhaken. Draveres Beispiel ist ja schön und gut, aber der Sinn erschließt sich mir nicht wirklich. Man kann solche Zeiger zwar super für Kommunikation benutzen, aber wie komt sone Kreisbewegung jetzt logisch zusammen?
Ich meine wenn ich 2 Klassen habe die Kommunizieren dann kann ich es doch genauso so machen:
class A { B* p; A() { p=new B(this); }; }; class B { A* p; B(A* pa) { p=pa; }; };Oder ich lasse den Faden ganz woanders raushängen, denn das Beispiel von Davere wäre ja ne kreisfahrt ohne raushängendes Ende mit dem man Kommunizieren kann.
-
Xebov schrieb:
Ich meine wenn ich 2 Klassen habe die Kommunizieren dann kann ich es doch genauso so machen:
Wobei du dich dann sowohl um das Speicherhandling, als auch die Benachrichtigung kümmern musst wenn ein Zeiger ungültig wird (mit shared_ptr und weak_ptr funktioniert dies auch, wenn mehrere Klassen und nicht nur 2 involviert sind perfekt).
cu André
-
Nur der Vollständigkeit halber: Man kann auch manuell den Kreis brechen
void foo() // Aus Draveres exzellentem Beispiel { MyClassAPtr objA(new MyClassA()); MyClassBPtr objB(new MyClassB()); objA->bPtr = objB; objB->aPtr = objA; objB->aPtr.reset(); // <- }