Schlanke Smartpointer-Implementierung?
-
RayOfLight schrieb:
Burkhi schrieb:
Das ist nun mal der Preis für ein bisschen mehr Komfort, genau wie im richtigem Leben.

Nur genau wie im richtigen Leben sollte auch die Verhältnismäßigkeit gegeben sein: in 4 KBytes bringt man ganze Grafikdemos samt Bildern, Sound und 3D Animationen unter, Boost benötigt 20 KBytes um ein paar Zähler zu bedienen und Speicher freizugeben (und ich rede wirklich von 20 KBytes effektivem Binärcode, der gesamte Executable/Linker-Overhead ist da schon gar nicht mitgezählt).
Absolut irrelevant. Der Code wird nicht auf diese Weise optimiert, weil 20K egal sind. Viel wichtiger ist es dass der Code schnell abläuft.
Und das bedeutet, dass der Code länger wird. Man kann ihn natürlich auch kleiner bekommen, nur hat man dann langsameren Code. Und das wollen die meisten Leute nicht, deshalb nimmt man halt die sinnvollste Optimierung.
Und shared_ptr ist ja auch nicht nur einfach ein Zeiger - das ist eine enorm komplexe Angelegenheit - ein bisschen mit einem GC vergleichbar.
-
Shade Of Mine schrieb:
Der Code wird nicht auf diese Weise optimiert, weil 20K egal sind. Viel wichtiger ist es dass der Code schnell abläuft.
Und das bedeutet, dass der Code länger wird. Man kann ihn natürlich auch kleiner bekommen, nur hat man dann langsameren Code.
Ähm...vielleicht solltest du dir meinen Link oben erst mal ansehen bevor du sowas öffentlich behauptest...
-
RayOfLight schrieb:
Shade Of Mine schrieb:
Der Code wird nicht auf diese Weise optimiert, weil 20K egal sind. Viel wichtiger ist es dass der Code schnell abläuft.
Und das bedeutet, dass der Code länger wird. Man kann ihn natürlich auch kleiner bekommen, nur hat man dann langsameren Code.
Ähm...vielleicht solltest du dir meinen Link oben erst mal ansehen bevor du sowas öffentlich behauptest...
Braucht er nicht, weil er recht hat. Das ist auf Größe optimierter Code, der sich zur Laufzeit auf gigantische Größen im Speicher auspackt, und zur Ausführung leistungsstarke Maschinen benötigt.
-
Shade Of Mine schrieb:
das ist eine enorm komplexe Angelegenheit
Eine sehr subjektive Behauptung. Ich finde shared_ptr ziemlich primitiv.
Shade Of Mine schrieb:
ein bisschen mit einem GC vergleichbar.
Ne, ein GC arbeitet komplett anders.
-
RayOfLight schrieb:
Ähm...vielleicht solltest du dir meinen Link oben erst mal ansehen bevor du sowas öffentlich behauptest...
In solchen Umfeldern wird man aber auch keine Smartpointer mit Referenzzählung verwenden, eben wegen ihren Overhead. Für die meisten Anwendungsfälle ist dieser Overhead wiederum absolut zu vernachlässigen.
Wenn man wirklich eine sehr kleine exe haben will, programmiert man in der Regel wesentlich mehr zu Fuß und optimiert wesentlich stärker. Für andere Anwendungen wiederum spielt die Entwicklungszeit (und damit der Komfort) eine wesentlich größere Rolle als beispielsweise 20kb.
-
Pis Halbwissen nervt (mal wieder).
-
Weil ich hier ja auch so viele Aussagen hingeschrieben habe, in denen Halbwissen überhaupt vorkommen könnte...

-
314159265358979 schrieb:
Eine sehr subjektive Behauptung. Ich finde shared_ptr ziemlich primitiv.
Hast du dir wirklich mal alle Fähigkeiten des shared_ptr angesehen (ich meine auch solche wie das zusammenspiel mit weak_ptr, enable_shared_from_this...)?
Man kann auch einfachere Implementierungen machen, wenn man auf das ein oder andere verzichten kann (z.B. auf den weak_ptr), ich hatte vor längeren in einer Firma händisch einen solchen in Anlehnung auf eine Implementierung von Scott Meyers geschrieben. Die war zwar schlanker, konnte aber auch wesentlich weniger (Mit einer Realisierung die stark an eine doppelt verkettete Liste erinnert hat, ohne einer Referenzzählung).
314159265358979 schrieb:
Shade Of Mine schrieb:
ein bisschen mit einem GC vergleichbar.
Ne, ein GC arbeitet komplett anders.
Die Grundidee geht aber in eine ähnliche Richtung, und der shared_ptr kommt den grundlegenden Denkansätzen eines GC doch schon nahe.
-
asc schrieb:
Hast du dir wirklich mal alle Fähigkeiten des shared_ptr angesehen (ich meine auch solche wie das zusammenspiel mit weak_ptr, enable_shared_from_this...)?
Ja.
asc schrieb:
Man kann auch einfachere Implementierungen machen, wenn man auf das ein oder andere verzichten kann (z.B. auf den weak_ptr), ich hatte vor längeren in einer Firma händisch einen solchen in Anlehnung auf eine Implementierung von Scott Meyers geschrieben. Die war zwar schlanker, konnte aber auch wesentlich weniger (Mit einer Realisierung die stark an eine doppelt verkettete Liste erinnert hat, ohne einer Referenzzählung).
Also reference linked Smartpointer.
-
In jedem seinem Posting merkt man, wie Pi nach Anerkennung bettelt.

-
Wenn man möglichst effizient und schlank bleiben wollen will, würde ich einfach eine Basis für reference-counted objects schreiben:
class reference_counted { private: std::atomic_uint m_ref; public: void inc_ref() { ++m_ref; } void dec_ref() { if(std::atomic_fetch_sub(&m_ref, 1) == 0) delete this; } };Und davon halt alle Klassen ableiten + einen smart pointer schreiben der nur inc_ref/dec_ref aufruft. Fertig.
-
Ich finde die Idee blöd, das Objekt die Lebenszeit managen zu lassen. Auf die hat es schlielich keinen Einfluss. Des Weiteren zwingst du damit den Instanzen einen Refcounter auf, auch wenn das Ding am Stack liegt.
-
Ethon schrieb:
Wenn man möglichst effizient und schlank bleiben wollen will, würde ich einfach eine Basis für reference-counted objects schreiben:
class reference_counted { private: std::atomic_uint m_ref; public: void inc_ref() { ++m_ref; } void dec_ref() { if(std::atomic_fetch_sub(&m_ref, 1) == 0) delete this; } };Und davon halt alle Klassen ableiten + einen smart pointer schreiben der nur inc_ref/dec_ref aufruft. Fertig.
Wenn man das unsinnige Ableiten weglässt, hat man wieder
shared_ptr.
Außerdem hast du vergessen, den Destruktor virtuell zu machen.
delete thisist ohnehin sehr unschön.
-
314159265358979 schrieb:
Ich finde die Idee blöd, das Objekt die Lebenszeit managen zu lassen. Auf die hat es schlielich keinen Einfluss.
D.h. ein std::vector sollte auch niemals seinen Inhalt managen, denn auf diesen hat er schliesslich keinen Einfluss.
Saudummes Argument.Intrusive Ref-Counting ist toll.
-
Wenn man das unsinnige Ableiten weglässt, hat man wieder shared_ptr.
shared_ptr kann funktionieren OHNE den ref-count auf dem Heap abzulegen?
Außerdem hast du vergessen, den Destruktor virtuell zu machen.
War ja nur ein Snippet.

delete this ist ohnehin sehr unschön.
Wenn es kontrolliert passiert, wieso?
Des Weiteren zwingst du damit den Instanzen einen Refcounter auf, auch wenn das Ding am Stack liegt.
Ich gehe mal davon aus, dass man einzelne Objekte nur auf dem Heap erzeugt, wenn sie primär da Sinn machen. Also in erster Linie für Laufzeit-Polymorphie, Factories etc.
-
Ethon schrieb:
Wenn man das unsinnige Ableiten weglässt, hat man wieder shared_ptr.
shared_ptr kann funktionieren OHNE den ref-count auf dem Heap abzulegen?
Nein, intrusive aber auch nicht. Im Speicher sehen beide gleich aus (selbstverständlich mit
make_shared).Ethon schrieb:
delete this ist ohnehin sehr unschön.
Wenn es kontrolliert passiert, wieso?
Weil es unlogisch ist, dass ein Objekt sich selbst zerstört. Es hat sich ja auch nicht selbst erstellt.
-
Ethon schrieb:
Wenn man das unsinnige Ableiten weglässt, hat man wieder shared_ptr.
shared_ptr kann funktionieren OHNE den ref-count auf dem Heap abzulegen?
shared_ptr kann - wenn man make_shared verwendet - ohne zusätzliche Allokation auskommen. Objekt + Deleter + Counter werden dann alle in einen einzigen Speicherblock reingepackt.
Das hat natürlich den Nebeneffekt, dass der Speicher für das gesamte Objekt + Counter erst freigegeben wird sobald der letzte weak_ptr darauf verschwindet.
-
hustbaer schrieb:
D.h. ein std::vector sollte auch niemals seinen Inhalt managen, denn auf diesen hat er schliesslich keinen Einfluss.
Saudummes Argument.Du bist echt dumm wie Stroh. Natürlich besitzt der vector seine Elemente, aber nicht sich selbst.
-
Hihi. Ja, wenn DU das sagst.
-
TyRoXx schrieb:
Ethon schrieb:
Wenn man möglichst effizient und schlank bleiben wollen will, würde ich einfach eine Basis für reference-counted objects schreiben:
class reference_counted { private: std::atomic_uint m_ref; public: void inc_ref() { ++m_ref; } void dec_ref() { if(std::atomic_fetch_sub(&m_ref, 1) == 0) delete this; } };Und davon halt alle Klassen ableiten + einen smart pointer schreiben der nur inc_ref/dec_ref aufruft. Fertig.
Wenn man das unsinnige Ableiten weglässt, hat man wieder
shared_ptr.
Außerdem hast du vergessen, den Destruktor virtuell zu machen.
delete thisist ohnehin sehr unschön.Ableiten ist schon sinnvoll um Code-Bloat zu vermeiden. Allerdings ist es immer noch Aufgabe des Smartpointers und nicht des Referenzcounters, dafür zur sorgen, dass das Objekt am Ende freigegeben wird. Und dann benötigt man auch keinen virtuellen Destruktor. atomic_fetch_sub gibt übrigens den alten Wert des Counters zurück...