Objekt einer Klasse: Selbstzerstörung



  • Hallo!
    Wie kann ich ein Object einer Klasse dazu bringen, sich selbst zu zerstören?
    Ich habe bisher folgendes versucht:

    #include <iostream>
    class A
    {
    public:
        A() {cout << "Self-Destruction" << endl;}
        void KillMe() {delete this;}
    };
    
    int main()
    {
        A Inst();
        Inst.KillMe();
        return 0;
    }
    

    Naja, also der Konstruktor wird zumindest schon mal aufgerufen, leider gibts dann einen Assertion-Fehler und schließlich dann stürzt das Programm ab.

    Würde mich sehr über Antworten freuen. 🙂



  • A *inst = new A();
    delete inst;
    inst = 0;
    

    Für etwas gibts ja den Destruktor 🙂



  • Danke für die Antwort!
    Aber wozu das "inst = 0;" ?
    Und außerdem wäre das ja nur eine Zerstörung von außen, und das genügt in dem Fall nicht (bzw. wäre etwas umständlich). Ich brauche eine Möglichkeit, wie sich das Objekt SELBST zerstören kann. Oder hab ich jetzt deinen Code nicht verstanden?
    Gruß. 🙂



  • Das = 0 (häufig =NULL) sorgt dafür, dass der Zeiger nicht versehens noch wo drauf zeigt und du ihn noch mal brauchst und im RAM rumstocherst.
    BTW: in deinem Beispiel zerstörst du das Objekt ja auch von aussen 😕



  • Das Problem bei dir liegt darin, dass du keinen Zeiger auf das Objekt erstellst und
    dann das Objekt löschst, obwohl es am Ende der Funktion doch automatisch gelöscht wird.

    Deshalb löschst du das Objekt 2 mal und daher der Absturz



  • das_brot schrieb:

    Das = 0 (häufig =NULL) sorgt dafür, dass der Zeiger nicht versehens noch wo drauf zeigt und du ihn noch mal brauchst und im RAM rumstocherst.

    Da hast du Recht. Hab ich gar nie dran gedacht...

    das_brot schrieb:

    BTW: in deinem Beispiel zerstörst du das Objekt ja auch von aussen 😕

    Im Prinzip schon, aber das "delete" wird in deinem Fall von außen ausgeführt. Ich wollte das halt in einer Funktion der Klasse selbst haben. Das liegt hieran:
    Die Klasse hat eine Update funktion, die immer wieder aufgerufen wird. Darin werden irgendwelche Bedingungen überprüft, und wenn sie erfüllt sind, soll sich das Objekt ohne weiteres Zutun von außen zerstören. Der Quelltext von oben war nur ein blödes Beispiel von mir. Wenn ich nämlich das "delete" nicht in einer Klasseninternen Funktion habe, muss ich irgendeine Nachricht nach außen schicken, den Zeiger mitteilen und das Objekt dann von irgendwo anders zerstören. War das verständlich? 😃



  • Ja.
    Aber:

    foo a;
    a.Update(); //macht Kill() weil bedingung erfüllt
    a.Anderefunktion(); //error
    

    Will sagen, du musst so oder so von aussen überprüfen ob die Instanz noch gültig ist. 😉



  • nicht, wenn die logik das verhindert, beispiele GUI:

    ein childfenster bekommt die nachricht, dass es sich zerstören soll. Das erste was es tut ist seinem parent mitzuteilen, dass es nichtmehr existiert, wonach es sich selbst vernichtet. Dies ist insofern besser, als das das parent fenster nicht wissen muss, wie child zu zerstören ist. ob nun ein "delete" benutzt werden muss, oder irgendwelche krummen funktionen aufgerufen werden müssen ist egal.



  • Da hast du auch Recht, doch kann so ein Problem nicht passieren, da ich eine Art programminterne "Registry" habe, in der verschiedene Objekte registriert sind. Die Kill-Funktion würde das Objekt erst wieder "abmelden", so dass es offiziell als "tot" gilt. Aber wie könnte ich denn jetzt die "Selbstzerstörung" machen? (Ich hoffe mal dir fällt nicht noch eine Begründung ein, warum ich doch von außen zerstören muss) 😃



  • @otze
    Ganz genau, nur dass es nicht nur für GUI sondern in dem Fall für einen selbstgeschriebenen Animationstyp handelt (das "Animationsobjekt" killt sich wenn die Animation um ist).

    sorry for doppelpost (unregistriert)



  • class SuicideClass
    {
    public:
    	void CommitSuicide()
    	{
    		delete this;
    	}
    };
    
    int _tmain(int argc, _TCHAR* argv[])
    {
    	SuicideClass *sc = new SuicideClass;
    	sc->CommitSuicide();
    	return 0;
    }
    

    Wobei zu beachten ist, das nach CommitSuicide kein delete mehr kommen darf, sonnst RT-error.



  • Sprich: Ich muss das Objekt dynamisch erzeugen (und nicht auf dem Stack, wie in meinem Beispiel). Danke!



  • Exakt, da der Compiler das Objekt sonst killen will, wenn es nicht mehr gültig ist -> 2facher Destruktoraufruf.
    Gern geschehen 😉



  • Warum geht folgendes?

    class foo
    {
        public:
            void KillMe() { delete this; }
            void TestMe() { cout << "Ich lebe noch" << endl; }
    
    };
    
    #pragma argsused
    int main(int argc, char* argv[])
    {
    
        foo* p = new foo;
    
        p->KillMe();
    
        p->TestMe();
    
    }
    


  • Gute Frage, das delete tut genau nix...



  • Laut Standard ist das Verhalten deines Beispiels undefiniert, sprich es kann alles passieren selbst funktionieren. Allerdings muss das auf anderen Compilern nicht der Fall sein.

    @otze bei GUIs halte ich die Anwendung von delete this für schlecht und ich bin mir ziehmlich sicher, dass da der Fehlerteufel wüten wird, spätestens wenn Ausnahmen fliegen.

    Ich würde es für besser halten den Widgets eine Verstecken und Zeigen Funktion zu geben und dann referenzzählende Smartpointer einzusetzen.



  • Was heisst, du must bei deiner programminternen Registry Klassen, die sich Unreggen auch gleich deleten.



  • Ben04 schrieb:

    @otze bei GUIs halte ich die Anwendung von delete this für schlecht und ich bin mir ziehmlich sicher, dass da der Fehlerteufel wüten wird, spätestens wenn Ausnahmen fliegen.

    da ein dtor eh keine exception werfen darf, seh ich grad nicht das mögliche fehlerpotential.

    Ich würde es für besser halten den Widgets eine Verstecken und Zeigen Funktion zu geben und dann referenzzählende Smartpointer einzusetzen.

    kannst du, hilft aber sicher nicht in jeder situation.



  • ein objekt, das sich selbst zerstört, ist wirklich keine gute idee. es sollte von dem programmteil zerstört werden, der es erzeugt hat.

    und was die update-sache angeht, da sehe ich zwei möglichkeiten:

    1. dein programm ruft regelmäßig die update-methode auf
      dann braucht update() nur einen bool-wert zurückzugeben, der dem aufrufenden programm mitteilt, ob das objekt zerstört werden will. oder umgekehrt: was passiert, wenn die update-methode aufgerufen wird, aber das objekt sich bereits selbst zerstört hat?

    2. die update-methode wird von einem separaten thread aufgerufen. dann lass das objekt vom thread erzeugen und wieder zerstören. ansonsten gilt das selbe wie in (1).



  • Das Problem das ich mit sich selbst zerstörenden Objekten habe ist, dass es entweder der Selbstmord gar nicht nötig ist oder es nur über Selbstmord zerstörbar ist.

    Beispiel: Wir haben ein Widget das sich bei anderen Widgets abmeldet und anschließend selbst zerstört. Das Abmelden kann eine Exception werfen. Da wir ja davon ausgehen, dass jedes sich zerstörendes Widgets sich auch abmeldet (ansonsten bräuchten wir keinen Selbstmord und könnten Abmeldung von Zerstörung trennen) können wir es nicht mehr einfach deleten weil das nicht vorgesehen ist. Da die Abmeldefunktion werfen kann, haben wir keine Funktion die im Fall eines Stackunwindings das Objekt zerstören könnte. Sprich wir können es nicht mehr an den Stack binden.

    Ich will jetzt nicht so weit gehen zu sagen, dass es nicht mehr möglich ist das ausnahmesicher zu machen allerdings sind die Mittel die gebraucht werden würden recht unorthodox und daher fehleranfällig.

    Vielleicht hattest du auch einen anderen Anwendungsfall im Kopf an den ich nicht gedacht habe allerdings bin ich bis jetzt fest davon überzeugt, dass delete this mehr Probleme schafft als es löst.


Anmelden zum Antworten