boost::weak_ptr...



  • theta schrieb:

    Und auch um dangling pointers zu verhindern.
    Simon

    Wie 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_ptr steigt.



  • 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.
    Simon

    Wie 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_ptr steigt.

    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.
    Simon

    Wie 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_ptr steigt.

    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_ptr eh nur mit shared_ptr -Objekten erzeugen. Und der generierende chared_ptr minimiert ja bereits die Wahrscheinlichkeit für hängende Zeiger. Und wenn ich das richtig sehe, kann man die verwalteten Objekte auch nicht direkt über einen weak_ptr referenzieren. Man muss also den Umweg über einen shared_ptr mit lock() 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_ptr nur in Verbindung mit shared_ptr Sinn (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 das shared_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.


  • Administrator

    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.
    Ein boost::weak_ptr kann diese Abhängigkeit nun in eine Richtung verringern, da ein boost::weak_ptr bei 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(); // <-
    }
    

Anmelden zum Antworten