Designfrage: Mehrfachvererbung / Interfaces



  • 314159265358979 schrieb:

    Intrusives Refcounting ist nicht nur durch shared_ptr austauschbar, mit shared_ptr kanns auch weak_ptr geben. Und wie schon gesagt ist manuelles Refcounting absoluter Käse. Ein release vergisst man schnell mal und bei Exception Safety brauchen wir gar nicht erst anfangen.

    Also sagste nur "wenn man es selber macht, muß man ein wenig aufpassen.
    Kein Argument für mich.

    Haste technische Aspekte, wie daß die Basisklasse SharedObject grundsätzlich einen virtuellen Destruktoraufruf feiern muß, während shared pointers in manchen Fällen ohne auskommen? Naja, war ein Versuch, trifft hier wohl nicht zu.

    Saug Dir mal was aus den Fingern, warum shared pointers grundsätzlich besser sind.



  • 314159265358979 schrieb:

    Intrusives Refcounting ist nicht nur durch shared_ptr austauschbar, mit shared_ptr kanns auch weak_ptr geben. Und wie schon gesagt ist manuelles Refcounting absoluter Käse. Ein release vergisst man schnell mal und bei Exception Safety brauchen wir gar nicht erst anfangen.

    Intrusive Pointer zählen auch selber. Du hast keine Ahnung, wie man das alles richtig einsetzt.

    Hier mal was ganz einfaches http://www.codeproject.com/Articles/8394/Smart-Pointers-to-boost-your-code
    Google mal ein bisschen, vor du weiter Müll von dir gibst.



  • volkard schrieb:

    Also sagste nur "wenn man es selber macht, muß man ein wenig aufpassen.
    Kein Argument für mich.

    Dann kann ich dir leider nicht helfen. Ist in etwa dasselbe wie RAII vs. Java try-catch-finally-close.

    volkard schrieb:

    Haste technische Aspekte, wie daß die Basisklasse SharedObject grundsätzlich einen virtuellen Destruktoraufruf feiern muß, während shared pointers in manchen Fällen ohne auskommen? Naja, war ein Versuch, trifft hier wohl nicht zu.

    Saug Dir mal was aus den Fingern, warum shared pointers grundsätzlich besser sind.

    Es ist einfach nicht die Aufgabe eines Objektes, seine eigene Lebenszeit zu managen. Das kann es auch gar nicht, da es auch nicht weiß, wie (Stack/Heap) es erstellt wurde. Das kann nur der Besitzer - und das ist der shared_ptr. Solche Objekte können also nur auf dem Heap angelegt werden.

    cdtgfvhbj schrieb:

    Intrusive Pointer zählen auch selber. Du hast keine Ahnung, wie man das alles richtig einsetzt.

    Hier mal was ganz einfaches http://www.codeproject.com/Articles/8394/Smart-Pointers-to-boost-your-code
    Google mal ein bisschen, vor du weiter Müll von dir gibst.

    Haha, sehr witzig. Ein Paradebeispiel für intrusives Refcounting ist Irrlicht. Sowas ekelhaftes und grundsätzlich falsches sieht man selten. Aber ich weiß doch worums euch wieder mal geht: Mich zu schikanieren. Ihr wisst selbst ganz genau, dass ich Recht habe. Und weil ich euch nicht nochmal für euch hinschreibe, was ihr eh schon wisst, behauptet ihr einfach, ich hätte keine Argumente. Stellt euch nicht so dumm.



  • 314159265358979 schrieb:

    cdtgfvhbj schrieb:

    Intrusive Pointer zählen auch selber. Du hast keine Ahnung, wie man das alles richtig einsetzt.

    Hier mal was ganz einfaches http://www.codeproject.com/Articles/8394/Smart-Pointers-to-boost-your-code
    Google mal ein bisschen, vor du weiter Müll von dir gibst.

    Haha, sehr witzig. Ein Paradebeispiel für intrusives Refcounting ist Irrlicht. Sowas ekelhaftes und grundsätzlich falsches sieht man selten.

    Keine Ahung was Irrlicht macht, aber scheint wohl kein Paradebeispiel zu sein.

    Aber ich weiß doch worums euch wieder mal geht: Mich zu schikanieren. Ihr wisst selbst ganz genau, dass ich Recht habe. Und weil ich euch nicht nochmal für euch hinschreibe, was ihr eh schon wisst, behauptet ihr einfach, ich hätte keine Argumente. Stellt euch nicht so dumm.

    Genau. 🙄

    hustbaer schrieb:

    Glaub was du willst.



  • 314159265358979 schrieb:

    volkard schrieb:

    Also sagste nur "wenn man es selber macht, muß man ein wenig aufpassen.
    Kein Argument für mich.

    Dann kann ich dir leider nicht helfen. Ist in etwa dasselbe wie RAII vs. Java try-catch-finally-close.

    Überhaupt nicht. RAII geht mit intrusivem Ref Counting wunderbar Hand in Hand, verwend ich in Zusammenhang mit COM die ganze Zeit. Abgesehen davon hast du mit shared_ptr grundsätzlich das Problem von wegen wo der Counter angelegt wird, der damit verbundene Overhead fällt bei intrusivem Ref Counting nicht an, bei shared_ptr lässt er sich nur teilweise vermeiden wenn man make_shared benutzt und die Implementierung schlau ist...



  • @dot
    Vergiss es, Pi hat wieder mal seinen "ICH HAB RECHT UND IHR SEID SO GEMEIN!!!!111elf" Overdrive aktiviert. (*)

    Das wird hier nix mehr.

    *: Ich frage mich wie lange es dauert bis ihm der endgültig das Hirn rausbrennt.



  • Bei shared_ptr lässt er sich immer vermeiden, vorausgesetzt, man hat eine ordentliche Implementierung. Die std-Implementierung gibt da zu wenige Garantien.



  • 314159265358979 schrieb:

    Bei shared_ptr lässt er sich immer vermeiden, vorausgesetzt, man hat eine ordentliche Implementierung. Die std-Implementierung gibt da zu wenige Garantien.

    Dein shared_ptr ist aber rein prinzipiell immer doppelt so groß wie ein vergleichbarer Smartpointer für intrusives Ref Counting, weil er zwei Pointer halten muss. Mit make_shared kannst du nur den Overhead eines zusätzlichen new sparen...aber wenn du meinst...



  • 314159265358979 schrieb:

    Bei shared_ptr lässt er sich immer vermeiden, vorausgesetzt, man hat eine ordentliche Implementierung. Die std-Implementierung gibt da zu wenige Garantien.

    Ach was, der SharedPointer owned den IntrusivePointer per Default!!! Alta, was kommste da mit deinem Ausreden.



  • Wenn man nur die shared_ptr Funktionalität ohne weak_ptr und Deleter braucht, könnte man sich sowas basteln (nur angedeutet, unvollständig):

    #include <iostream>
    #include <utility>
    #include <cstddef>
    
    template <typename T>
    struct my_shared_ptr
    {
    	my_shared_ptr() : rc(0) {}
    
    	template <typename... Args>
    	my_shared_ptr(Args&&... args)
    		: rc(new refcount_block(std::forward<Args>(args)...))
    	{}
    
    	T& operator * ()
    	{
    		return *rc->ptr();
    	}
    
    	T* operator -> ()
    	{
    		return rc->ptr();
    	}
    
    	~my_shared_ptr()
    	{
    		if(!--rc->refs)
    			delete rc;
    	}
    
    private:
    	struct refcount_block
    	{
    		template <typename... Args>
    		refcount_block(Args&&... args)
    			: refs(1)
    		{
    			new (object) T(std::forward<Args>(args)...);
    		}
    
    		~refcount_block()
    		{
    			ptr()->~T();
    		}
    
    		T* ptr()
    		{
    			return reinterpret_cast<T*>(object);
    		}
    
    		std::size_t refs;
    		char object[sizeof(T)]; // alignas(T)
    	};
    
    	refcount_block* rc;
    };
    
    int main()
    {
    	std::cout << sizeof(int*)                 << '\n'
    	          << sizeof(my_shared_ptr<int>)   << '\n';
    }
    

    http://ideone.com/aIlrW
    Kann genau das, was man mit intrusivem Referenzzählen auch machen kann...

    Edit: Das mit dem rohen char-Array ist natürlich Blödsinn, ein normaler T geht auch. Aber ich bin jetzt zu faul, das noch zu ändern. :p



  • Damit hast du nun einfach das make_shared fix in den shared_ptr gebaut, was semantisch etwas anderes ist. Dein Pointer kümmert sich nun nicht nur um das Verwalten, sondern auch um das Erzeugen der Objekte...



  • Was aber aufs selbe hinausläuft wie beim intrusiven. Dort erstellst du ein T mit Args..., hier ists eben ein shared_ptr<T> mit Args....



  • Beim intrusiven schreibt mir niemand vor wie ich das Objekt zu erzeugen habe...



  • Du kannst meinen shared_ptr natürlich auch noch mit einem Allokator würzen, war ja nur skizziert. 😉



  • Lassen wir das und kehren wir vielleicht mal zur ursprünglichen Frage zurück:

    dot schrieb:

    Baldur schrieb:

    Wenn ich zum Beispiel nun in meinem Spiel ein Dialogfeld anzeige, kann man natürlich sagen, das Dialogfeld gehört dem Application Objekt und soll von diesem gelöscht werden, wenn ich es schließe.

    Mit anderen Worten: Du möchtest dass das Dialogfeld ein Member der Application ist...

    Baldur schrieb:

    Aber wie sieht es mit den Buttons oder Textfeldern auf dem Dialogfeld aus? Eigentlich möchte ich doch lieber, daß die mit dem Dialogfeld direkt mit gelöscht werden, und mir keine Liste mit Objekten merken, bzw. wann die gelöscht werden dürfen.

    Mit anderen Worten: Du möchtest dass die Buttons und Textfelder Member des Dialogfeldes sind...

    Baldur schrieb:

    Oder ich will einen Scene-Wechsel mit Hilfe einer Transition durchführen, dann möchte ich, daß die Transition mein altes Scene-Objekt löschen kann, sobald die Transition beendet ist.

    Lässt sich z.B. über std::unique_ptr machen. Was du da beschreibst, klingt mir eher nach Ownership-Transfer und nicht nach shared Ownership...

    Baldur schrieb:

    Und natürlich gibt es Fälle wie den obigen, daß z.B. ein TouchHandler ein Objekt behalten kann, was sonst bereits gelöscht wäre.

    Wieso genau muss der TouchHandler das so machen?



  • So ganz das Ursprungsthema ist es ja nicht, aber ich will mal versuchen es zu erklären.

    Das mit dem Dialogfeld war ein Beispiel. Ein anderes Beispiel wären Resourcen wie Images oder Texturen, die von mehreren Objekten verwendet werden, und gelöscht werden sollen, wenn das letzte Objekt, das es verwendet, stirbt.

    Sicher kann ich vieles davon auch mit shared_ptr, unique_ptr, etc umsetzen, allerdings hat es bisher auch recht gut mit dem bisherigen System funktioniert. Ja, es kann passieren, daß ich ein retain oder release vergessen, bisher war das aber tatsächlich nie ein größeres Problem. Vergessene releases ließen sich mit valgrind immer sehr effektiv auffinden.

    Aber wie gesagt, ich bin besseren Lösungen gegenüber ja durchaus offen, wenn es sich wirklich als besser erweist. Bisher wurden hier aber nicht viele Argumente genannt, aueßr eben daß es automatisch geht.

    Nun, wo sich das Thema schon in eine Diskussion über Smartpointer geändert hat, wäre dann wohl meine Frage, ob mit shared_ptr auch etwas in der Art umsetzbar wäre (wie gesagt, hab mich noch nicht ganz so tief damit auseinander gesetzt, ist jetzt auch eher ein wenig Pseudo-Code, weil ausm Kopf geschrieben)

    class Node {
        void addChild(shared_ptr<Node*> child)
    }
    
    ...
    
    shared_ptr<MyMagicButton*> button = new MyMagicButton();
    myNode->addChild(button);
    


  • Ja, das funktioniert - abgesehen davon, dass man dem shared_ptr nicht den Zeigertyp sondern den Typ, auf den gezeigt werden soll übergibt. Und was intrusive Zeiger angeht, kannst du das in einen intrusive_ptr wrappen, dann hast du intrusives Reference Counting und trotzdem automatisch.



  • @314159265358979
    Dein hier skizzierter shared_ptr ist intrusive, denn man kann nicht mehr einfach Objekte die man von irgendwoher bekommt reinstecken.

    @Baldur
    Ja, man kann ganz normal () casten und Upcasts sind weiterhin implizit. ( man muss nur boost::xxx_pointer_cast<>() statt xxx_cast<>() verwenden)

    Was nicht mehr geht (oha, ein Nachteil von shared_ptr der ja angeblich keine Nachteile hat, na sowas), ist ... wenn du nen rohen Zeiger bekommst kannst du keinen shared_ptr mehr draus machen, d.h. du kannst kein "retain" machen.



  • hustbaer schrieb:

    Was nicht mehr geht (oha, ein Nachteil von shared_ptr der ja angeblich keine Nachteile hat, na sowas), ist ... wenn du nen rohen Zeiger bekommst kannst du keinen shared_ptr mehr draus machen, d.h. du kannst kein "retain" machen.

    _Was genau_ geht hier angeblich mit shared_ptr nicht?



  • 314159265358979 schrieb:

    hustbaer schrieb:

    Was nicht mehr geht (oha, ein Nachteil von shared_ptr der ja angeblich keine Nachteile hat, na sowas), ist ... wenn du nen rohen Zeiger bekommst kannst du keinen shared_ptr mehr draus machen, d.h. du kannst kein "retain" machen.

    _Was genau_ geht hier angeblich mit shared_ptr nicht?

    Du kannst diese Funktion nicht implementieren:

    // p zeigt auf ein Objekt das bereits von einem shared_ptr kontrolliert wird
    shared_ptr<Thing> GetSharedPtr(Thing* p)
    {
        return ...?
    }
    

    Mit einem klassischen intrusive_ptr ist das überhaupt kein Problem.


Anmelden zum Antworten