Virtueller Destruktor, wenn eigentlich keiner benötigt wird



  • Also falls ein Objekt über einen Basisklassenzeiger deleted werden kann, sollte der Basisklassen-Destruktor ja virtuell sein. So als Faustregel.

    Was aber wenn ich eigentlich garnkeinen Destrukor benötige? Wenn ich also nicht mit rohem Speicher oder anderen Ressourcen hantiere. Soll (oder muss) dann ein leerer virtueller Destruktor in die Basisklasse aufgenommen werden?



  • "Wenn ich also nicht mit rohem Speicher oder anderen Ressourcen hantiere."

    Innerhalb der Klasse, meine ich damit! Außerhalb natürlich schon, denn wir legen die Objekte ja mit new an und wollen sie mit einem Basisklassenzeiger löschen.


  • Mod

    Das betrifft hier viel grundlegendere Dinge als dynamischen Speicher: Die Member selbst werden dann nicht richtig freigegeben. Destruktoren werden schließlich rekursiv aufgerufen:

    class Base
    {
     Member member;
    };
    
    class Derived: public Base
    {
     OtherMember other_member;
    };
    
    // ...
    Base *foo = new Derived;
    Derived *bar = new Derived;
    // ...
    
    delete bar; // Alles wird aufgeräumt
    delete foo; // Oh nein, der Destruktor von OtherMember (und der von Derived) wird nicht aufgerufen!
    

    Die abgeleitete Klasse sollte also besser keine eigenen Member haben, wenn der Destruktor nicht virtuell ist. Fragt sich dann bloß, wozu die abgeleitete Klasse gut sein soll, wenn sie nur Funktionen bietet. Das deutet meistens darauf hin, dass eigentlich freie Funktionen mit einem Base als Parameter eher angesagt wären.

    Falls du glaubst, dass du dein Programm super beschleunigen kannst, indem du dir den virtuellen Destruktor sparst: Höchstwahrscheinlich bringt es überhaupt nichts. Wie oft wird der schon aufgerufen? Und wenn du mit Basisklassenzeigern hantierst hast du ja meistens sowieso Polymorphie und damit noch weitere virtuelle Funktionen.



  • Ok, danke.

    Also ist die Lösung ein virtueller Destruktor mit leerem Rumpf in der Basisklasse.


  • Mod

    Wenn in einer delete-Anweisung der statische Typ des Objekts, auf das der übergebene Zeiger zeigt, nicht mit dem dynamischen Typ übereinstimmt (also delete über ein Basisklassensubobjekt verwendet wird) und der statische Typ nicht über einen virtuellen Destruktor verfügt, ist das Verhalten undefiniert. Es kommt nicht darauf an, wie das Objekt konkret aufgebaut ist und ob evtl. im Destruktor eigentlich nichts weiter zu tun ist.



  • camper schrieb:

    Wenn in einer delete-Anweisung der statische Typ des Objekts, auf das der übergebene Zeiger zeigt, nicht mit dem dynamischen Typ übereinstimmt (also delete über ein Basisklassensubobjekt verwendet wird) und der statische Typ nicht über einen virtuellen Destruktor verfügt, ist das Verhalten undefiniert. Es kommt nicht darauf an, wie das Objekt konkret aufgebaut ist und ob evtl. im Destruktor eigentlich nichts weiter zu tun ist.

    Also kurz: das ist UB?

    struct A {};
    struct B : A {};
    
    int main()
    {
        delete (A*)new B;
    }
    

  • Mod

    Sone schrieb:

    camper schrieb:

    Wenn in einer delete-Anweisung der statische Typ des Objekts, auf das der übergebene Zeiger zeigt, nicht mit dem dynamischen Typ übereinstimmt (also delete über ein Basisklassensubobjekt verwendet wird) und der statische Typ nicht über einen virtuellen Destruktor verfügt, ist das Verhalten undefiniert. Es kommt nicht darauf an, wie das Objekt konkret aufgebaut ist und ob evtl. im Destruktor eigentlich nichts weiter zu tun ist.

    Also kurz: das ist UB?

    struct A {};
    struct B : A {};
    
    int main()
    {
        delete (A*)new B;
    }
    

    ja. 5.3.5/3



  • Klassen die in der Liste der Liste der Basisklassen stehen, sollen entweder ein public virtual ODER einen protected non-virtual Destruktor haben.


Log in to reply