Anwendungszweck von shared_ptr<T>?
-
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!
-
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_ptrexistiert.Edit³: Wie zum Teufel entfernt man aus einer
forward_listein 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.

-
Sone schrieb:
Wie zum Teufel entfernt man aus einer
forward_listein 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.
-
volkard schrieb:
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.
Hmm, ich habe letztens erst nen Loader für den Texturen geschrieben.
Der hat die Texturen in einen shared_ptr geladen, wenn die Textur nochmal angefordert wurde gabs den shared_ptr zurück.
Sporadisch wurden alle shared_ptr im Loadercache geprüft ob der Loader die letzte Referenz hält (use_count()) und falls ja wurde der ptr gelöscht.Schlechtes Design oder sinnvoller Einsatzzweck?
Was wäre besser?
-
@Ethon das kann man mit weak_ptr verbessern. Ansonsten, generell einen shared_ptr auf eine Textur finde ich nicht schlecht, aber ob man überhaupt noch "manuell" einen Cache dazubauen muss ist dann wieder irgendwie fragwürdig, warum sollte man zwei mal die gleiche Textur laden.
-
Ethon schrieb:
Sporadisch wurden alle shared_ptr im Loadercache geprüft ob der Loader die letzte Referenz hält (use_count()) und falls ja wurde der ptr gelöscht.
Schlechtes Design oder sinnvoller Einsatzzweck?
Was wäre besser?use_count()==17 hattest Du niocht wissen wollen.
Nur use_count()!=0.
Also nur is_used().edit:
Nur use_count()!=1.
Also nur is_other_used().
Auch im Ring mit O(1).
-
§ 20.7.2.2.5/8 schrieb:
[ Note: use_count() is not necessarily efficient. — end note ]
-
Genau für solche Fälle gibts ja
shared_ptr::unique().Aber auch das braucht man recht selten. Ich hab
unique()nur einmal bei einer ziemlich unkonventionellen Ressourcenverwaltung benötigt. Inzwischen ist mir aber klar geworden, dass es in vielen Fällen einfacher geht. Designs mitshared_ptrhaben die Tendenz zu hoher Komplexität und Unklarheit über Besitzverhältnisse.
-
Alles, was ich bisher gehört habe, fällt unter
shared_ptr schrieb:
shared_ptr<const T> als Copy-Optimierung macht auch Sinn (also shared_ptr mit immutable Objekten).
Das macht man zwar nicht häufig, kommt aber von Zeit zu Zeit vor und ist aus meiner Sicht absolut legitim.
-
cooky451 schrieb:
Vielleicht wenn mehrere Threads das gleiche Objekt besitzen?
-
cooky451 schrieb:
cooky451 schrieb:
Vielleicht wenn mehrere Threads das gleiche Objekt besitzen?
Darunter konnte ich mir nur was vorstellen, wenn das Objekt immutable ist.
Könntest du kurz erklären?