enable_shared_from_this



  • Doku gelesen - WTF-Moment - Nicht verstanden.
    Wozu brauch ichs?





  • Ich sehe trotzdem keinen Nutzen darin, und verstehe auch nicht wirklich, wie das funktioniert.



  • Die Sache ist die: shared_ptr erwartet, dass es für ein gegebenes Objekt genau einen shared_ptr gibt, der mit einem normalen Pointer auf das Objekt initialisiert wird (idealerweise direkt bei/nach dem new-Aufruf), und dass alle weiteren shared_ptr auf das Objekt Kopien dieses originalen shared_ptr sind.
    Der Grund ist der Referenz-Zähler. Wenn du einem shared_ptr Konstruktor einen normalen Pointer übergibst, muss er davon ausgehen, dass er der "erste" shared_ptr auf das Objekt ist und legt einen Referenzzähler mit dem Wert 1 an. Wenn du einen shared_ptr kopierst, teilen sie sich den Referenzzähler, der bei jeder Kopie inkrementiert wird und in Destruktoren, release-aufrufen und wann immer ein shared_ptr sein Objekt "loslässt" dekrementiert wird. Fällt der Zähler auf 0, wird das Objekt zerstört.

    In manchen Fällen macht es Sinn, dass Methoden this-Pointer zurückgeben. Wenn jetzt stattdessen ein shared_ptr auf das Objekt zurückgegeben werden soll, ist das nicht so einfach:

    struct S
    {
      shared_ptr<S> foo() {return shared_ptr<S>(this); } //1
    };
    
    int main()
    {
      shared_ptr ps(new S();); //0
    
      {
        shared_ptr ps2 = ps->foo(); //2
      } //3
    
    } //4
    

    Folgendes passiert an den numerierten Kommentaren:
    0) ps legt eine Refcounter R1 für das Objekt an, Wert wird auf 1 gesetzt.

    1. es wird ein temporärer shared_ptr mit dem this-Pointer des Objektes initialisiert. Da der this-Pointer ein normaler S ist, wird ein neuer Refcounter R2 angelegt*
    2. ps2 kopiert vom temporären shared_ptr, benutzt also auch R2. Nachdem der temporäre shared_ptr erledigt ist, steht R2 auf 1 (ps2 ist der einzige shared_ptr mit diesem Refcounter)
    3. ps2 geht aus dem Scope, im Dtor wird R2 auf 0 gesetzt und deshalb das Objekt zerstört.
    4. ps geht aus dem Scope, im Dtor wird R1 auf 0 gesetzt und das Objekt nochmal zerstört. BUMM...

    enable_shared_from_this sorgt vermutlich einfach dafür, dass der refcounter bereits am Objekt existiert und nicht außerhalb von den shared_ptrn angelegt wird. Wenn man einen shared_ptr von einem solchen Objekt anlegt, wird einfach der bereits vorhandene Refcounter erhöht, egal ob es sich um einen simplen pointer oder einen shared_ptr handelt.
    Ich schreibe vermutlich, weil ichs nicht genau weiß - der shared_ptr Header wirds dir zeigen 🙂



  • Das ist ja alles schön und gut (Danke für deine Erklärung übrigens) - aber - wozu brauch ich sowas? Warum sollte ich einen shared_ptr auf this zurückgeben wollen? Vielleicht sitzt das Problem auch an anderer Stelle - ich verwende shared_ptr nie, weil ich ihn bisher noch nicht gebraucht habe. Ja, unique_ptr war für meine Zwecke bisher immer völlig ausreichend.



  • 314159265358979 schrieb:

    Das ist ja alles schön und gut (Danke für deine Erklärung übrigens) - aber - wozu brauch ich sowas? Warum sollte ich einen shared_ptr auf this zurückgeben wollen? Vielleicht sitzt das Problem auch an anderer Stelle - ich verwende shared_ptr nie, weil ich ihn bisher noch nicht gebraucht habe. Ja, unique_ptr war für meine Zwecke bisher immer völlig ausreichend.

    Das setzt voraus, dass man unique_ptr hat. Ansonsten hat man man, insbesondere in Verbindung mit bind-Ausdrücken und gebundenen Smart-Pointer-Objekten, eigentlich nur die Option einen shared_ptr zu nehmen. Ansonsten guck Dir mal die boost.asio -Beispiele an. Zum Beispiel die Chat-Session (in der server.cpp). Da wird shared_from_this benutzt, und da steht auch, warum das toll ist.



  • 314159265358979 schrieb:

    wozu brauch ich sowas? Warum sollte ich einen shared_ptr auf this zurückgeben wollen?

    Warum Du das brauchen solltest, weiß ich nicht. Ich nutze shared_ptr sonst auch nicht. Aber ich kann mir schon vorstellen, dass das praktisch sein kann. Z.B. wenn sich das Objekt selbstständig irgendwo "registrieren" will und dies eben über ein shared_ptr machen will. Warum denn auch nicht? Ist Dein Tellerrand zu hoch?



  • Also ich habe es schon oft gebraucht. Was ist daran so schwer zu verstehen, das ein verwaltetes Objekt, sich auch mal "verwaltet" übergeben muß? Mit this übergibst du halt nur den unverwalteten Zeiger, mit enable_shared_from_this ist es der verwaltete Zeiger. 🙄



  • Ihr versteht mein Problem nicht - Ich habe ja verstanden, was es tut (auch wenn mir immer noch nicht klar ist, wie es das tut.)
    Ich kann mir dennoch unter "Es gibt einen korrekten shared_ptr auf this zurück" schwer vorstellen, wie ich das verwenden kann.



  • krümelkacker schrieb:

    Z.B. wenn sich das Objekt selbstständig irgendwo "registrieren" will und dies eben über ein shared_ptr machen will.

    Gutes Beispiel 🙂

    class Registry 
    { /* ... */
    
      void register(shared_ptr<RegisteredObject> newObject); 
    };
    
    class RegisteredObject
    {
    public:
      RegisteredObject()
      {
        /* ... */
        Registry::instance().register(shared_from_this()); 
      }
    };
    


  • oder:

    class some_class
    {
    
        std::function<void (other_class const & c)> get_callback(){ return std::bind(&this_class::other_class_input, shared_from_this(), _1); }
    
    };
    

Anmelden zum Antworten