Anwendungszweck von shared_ptr<T>?



  • volkard schrieb:

    shared_ptr schrieb:

    Gibt es einen sinnvollen Anwendungszweck von shared_ptr<T>? Also einer, der nicht auf schlechtes Design zurückzuführen ist.

    Ein Sender schickt Jobs an mehrer Empfänger und alle können damit was tun. Nur interessiert es den Sender nicht, wann und ob sie jeweils ihren Job verarbeiten, er muss sie nur benachrichtigt haben. Der letze, der den Job verarbeitet oder ignoriert, macht das List aus. Zum Beispiel in einem Netzwerksimulator die Pakete, die über den Bus gehen.

    Das wäre dann shared_ptr mit immutable-Objekten oder nicht? Das ist nämlich ok.

    Sone schrieb:

    Sondern es ist ein hilfreiches Prinzip, dass bestimmte Designs einfacher [zu implementieren] macht.

    Im Gegenteil, shared_ptr ist die Hölle! Du kannst überhaupt gar nichts über den Zustand des Objekts sagen, da er sich jederzeit ändern könnte.



  • Sone schrieb:

    Zwei Fragen:

    • Sind die Jobs so teuer zu kopieren?
    • Wieso besitzen die Empfänger die Jobs?

    Edit:

    Zum Beispiel in einem Netzwerksimulator die Pakete, die über den Bus gehen.

    Das hast du aber hinterhereditiert.

    Jo, hab konkretisiert.
    Die Jobs sind teuere zu kopieren als der shard_ptr-Trick. Sie besitzen, weil der Sender sie echt loslassen will.
    Also eigentlich nur ein Implementierungsdetail, um Speed zu machen. Da habe ich es benutzt.

    Wo braucht man sie wirklich?



  • Soll eigentlich ein shared_ptr durch eine interne Map implementiert werden? Wenn ich irgendwo zwei shared_ptr erzeuge, die die gleiche Adresse besitzen, ist dann alles definiert?



  • Sone schrieb:

    Soll eigentlich ein shared_ptr durch eine interne Map implementiert werden? Wenn ich irgendwo zwei shared_ptr erzeuge, die die gleiche Adresse besitzen, ist dann alles definiert?

    facepalm++



  • Schon gut, ein ref counter, war doch klar.



  • Vielleicht wenn mehrere Threads das gleiche Objekt besitzen?



  • Ich benutze shared_ptr z.B., um ungenutze Objekte in einen Cache zu werfen (Custom Deleter).



  • Sone schrieb:

    Soll eigentlich ein shared_ptr durch eine interne Map implementiert werden? Wenn ich irgendwo zwei shared_ptr erzeuge, die die gleiche Adresse besitzen, ist dann alles definiert?

    Das ist der Grund warum std::shared_from_this existiert.
    Wäre mit ner Map ja obsolet.

    Obwohl das mit der Map garnicht mal so schlecht sein muss.

    ---

    Edit. Um was zum Thema beizutragen:
    Ich bastle gerade an einer Skriptsprache und nutze shared_ptr anstatt einem GC für die Speicherverwaltung. Vermutlich schlechtes Design.
    Wollte es nur erwähnt haben.



  • Sone schrieb:

    Schon gut, ein ref counter, war doch klar.

    Und die andere wichtige Implementierung?



  • Ethon schrieb:

    Edit. Um was zum Thema beizutragen:
    Ich bastle gerade an einer Skriptsprache und nutze shared_ptr anstatt einem GC für die Speicherverwaltung. Vermutlich schlechtes Design.
    Wollte es nur erwähnt haben.

    Ich weiß. Bin gespannt, wie Du die zyklischen Referenzen findest. Halt uns auf dem Laufenden!


  • Mod

    volkard schrieb:

    Sone schrieb:

    Schon gut, ein ref counter, war doch klar.

    Und die andere wichtige Implementierung?

    über verkettete Zeiger? macht das noch jemand?



  • Ich denke gerade nach, was verkettete Zeiger sein könnten. Fungiert der shared_ptr wie ein Listenknoten, und hält einen Zeiger auf den nächsten shared_ptr ? Dann würde use_count() aber eine lineare Komplexität haben, das ist AFAICS nicht verkraftbar.

    Edit: Das funktioniert auch gar nicht.

    Edit²: Doch, das funktioniert. Der shared_ptr entfernt sich selbst aus der "Liste", sobald er zerstört wird. Anschließend prüft ein shared_ptr bei der Zerstörung immer, ob ein nächster shared_ptr existiert.

    Edit³: Wie zum Teufel entfernt man aus einer forward_list ein Element!? Wie wird der vorige Knoten verändert?

    Edit^4: Ich habe das Gefühl, das ist nicht das, was camper meinte. Zu hülf, camper! Was tatst du meinen?



  • Höh? Ein shared_ptr legt im Normalfall ein atomic_int auf dem Heap an und zählt damit.

    Edit³: Wie zum Teufel entfernt man aus einer forward_list ein Element!? Wie wird der vorige Knoten verändert?

    Geht ja per Iterator nicht. Man iteriert durch und merkt sich halt immer den letzten Knoten.

    Edit: Stop. Eine schlaue Implementierung könnte ja im Iterator den letzten Knoten halten. Dann geht's.

    volkard schrieb:

    Ethon schrieb:

    Edit. Um was zum Thema beizutragen:
    Ich bastle gerade an einer Skriptsprache und nutze shared_ptr anstatt einem GC für die Speicherverwaltung. Vermutlich schlechtes Design.
    Wollte es nur erwähnt haben.

    Ich weiß. Bin gespannt, wie Du die zyklischen Referenzen findest. Halt uns auf dem Laufenden!

    Hab da ein paar Ideen die aber alle recht imperformant klingeń.
    Vermutlich wird's ein GC, der steht sowieso auf der Muss-man-mal-implementiert-haben Liste.



  • Ethon schrieb:

    Höh? Ein shared_ptr legt im Normalfall ein atomic_int auf dem Heap an und zählt damit.

    Ja, das ist die Standardimplementierung, ein ref counter, wie bereits erwähnt.



  • camper schrieb:

    über verkettete Zeiger? macht das noch jemand?

    Gebe zu, ist stark im Abnehmen.



  • Sone schrieb:

    Ich denke gerade nach, was verkettete Zeiger sein könnten. Fungiert der shared_ptr wie ein Listenknoten, und hält einen Zeiger auf den nächsten shared_ptr ? Dann würde use_count() aber eine lineare Komplexität haben, das ist AFAICS nicht verkraftbar.

    Da aber in 100 Jahren Informatikgeschichte ausßer zum Debuggen kein use_count() auf shared_pointers benötigt wurde, ist das jetzt nicht wirklich das zwingende Argument.



  • Da aber in 100 Jahren Informatikgeschichte

    Ich hoffe, die 100 Jahre sind eine Hyperbel.

    Also hatte ich Recht? Hmm, das scheint intuitiv gut zum debuggen sein, da man so alle shared_ptr's sehen kann, welche das Objekt besitzen. 👍


  • Mod

    Sone schrieb:

    Wie zum Teufel entfernt man aus einer forward_list ein Element!? Wie wird der vorige Knoten verändert?

    Indem man die ganze Liste, die nat. zyklisch ist, durchläuft. Oder indem man gleich doppelt verkettet. Mit Threads wird es noch ein bisschen komplizierter. Wenn man keinen Mutex verwenden will, kann man hazard pointer verwenden. Wer Glück hat, kann DCAS (double word compare and swap) verwenden, existiert nur leider auf vielen Plattformen - wie z.B. x86 - nicht. Ist umständlich und die Korrektheit der Implementation schwer nachzuweisen.



  • Also die einfachste Antwort, wenn man es in Kombination mit weak_ptr einsetzt um eine Art Cache zu realisieren, wie Herb Sutter in seinem Going Native 2013 Vortrag gezeigt hat.

    camper schrieb:

    volkard schrieb:

    Sone schrieb:

    Schon gut, ein ref counter, war doch klar.

    Und die andere wichtige Implementierung?

    über verkettete Zeiger? macht das noch jemand?

    Hmm, wahrscheinlich jede Scheme/Lisp-Implementation.



  • Sone schrieb:

    Da aber in 100 Jahren Informatikgeschichte

    Ich hoffe, die 100 Jahre sind eine Hyperbel.

    Jo.

    Sone schrieb:

    Also hatte ich Recht? Hmm, das scheint intuitiv gut zum debuggen sein, da man so alle shared_ptr's sehen kann, welche das Objekt besitzen. 👍

    Das wäre natürlich ein doppelt verketteter Ring. Man muß sich "nur" mit seinen beiden Nachbarn einig werden und nicht mit allen 256 Prozessoren. Inwiefern das besser ist? Weiß noch nicht. Zur Zeit ist es lahm.


Anmelden zum Antworten