Wie löscht man die Instanz der Basisklasse?



  • Hi,

    in meinem Programm wird im Konstruktor einer erbenden Klasse die Basisklasse aufgerufen:

    Child::Child() : Parent() {
    ...
    }
    

    Im Destruktor von "Child" gebe ich die Membervariablen frei, was aber passiert mit der Parent-Instanz? Wie kann ich den damit verbundenen Speicher wieder freigeben?
    Wird der Destruktor von Parent automatisch gerufen, wenn ich
    delete myChild;
    aufrufe?

    Gruß, Thomas.



  • Sofern der dtor virtual ist wird erst der Destruktor der abgeleiteten und dann (automatisch) der der Basisklasse aufgerufen.



  • Der Destruktor braucht noch nicht mal virtuell zu sein. Der Destruktor der Basisklasse wird immer aufgerufen, wenn das Objekt zerstört wird.

    Ausserdem brauchst Du den leeren Konstruktor der Basisklasse nicht explizit aufzurufen. Es geht auch mit:

    Child::Child() {
    ...
    }
    

    Hier wird automatisch der Konstruktor ohne Parameter der Basisklasse aufgerufen.

    Tntnet



  • tntnet schrieb:

    Der Destruktor braucht noch nicht mal virtuell zu sein. Der Destruktor der Basisklasse wird immer aufgerufen, wenn das Objekt zerstört wird.

    Nein. Wenn der Destruktor der Basisklasse nicht virtuell ist, ist das Verhalten beim delete undefiniert. Und undefiniert ist boese!


  • Mod

    Apollon schrieb:

    tntnet schrieb:

    Der Destruktor braucht noch nicht mal virtuell zu sein. Der Destruktor der Basisklasse wird immer aufgerufen, wenn das Objekt zerstört wird.

    Nein. Wenn der Destruktor der Basisklasse nicht virtuell ist, ist das Verhalten beim delete undefiniert. Und undefiniert ist boese!

    es ist nur undefiniert, wenn das argument des delete ein zeiger auf diese basisklasse ohne virtuellen destruktor ist. es gibt keinen hinweis, dass das hier der fall sein soll.



  • class A
    {
      public:
        ~A()  { std::cout << "Destruktor A" << std::endl; }
    };
    
    class B : public A
    {
      public:
        ~B()  { std::cout << "Destruktor B" << std::endl; }
    };
    
    void f()
    {
      A* a = new B();
      delete a;      // hier wird nur der Destruktor von A aufgerufen,
                     // da der Zeiger vom statische Typ A* ist
    
      B* b = new B();
      delete b;      // hier wird erst ~B, dann ~A aufgerufen, also korrekt,
                     // obwohl der Destruktor nicht virtuell ist
    }
    

    Im Gegesatz dazu:

    class A
    {
      public:
        virtual ~A()  { std::cout << "Destruktor A" << std::endl; }
    };
    
    class B : public A
    {
      public:
        ~B()  { std::cout << "Destruktor B" << std::endl; }
    };
    
    void f()
    {
      A* a = new B();
      delete a;      // hier wird der Destruktor von B und dann der Destruktor A aufgerufen,
                     // da der Compiler weiß, daß er den Destruktor von A über die
                     // vtable adressieren muß, da er ja virtuell ist
    
      B* b = new B();
      delete b;      // hier wird erst ~B, dann ~A aufgerufen
    }
    

    Fazit: Der Destruktor muß nur dann virtuell sein, wenn ich einen delete über einen Zeiger auf die Basisklasse ausführe. Destruktoren verhalten sich da genau so, wie Methoden.

    Ich könnte ja hier noch ein Beispiel mit Methoden bringen:

    class A
    {
      public:
        virtual v()  { std::cout << "A::v" << std::endl; }
        f()  { std::cout << "A::f" << std::endl; }
    };
    
    class B : public A
    {
      public:
        virtual v()  { std::cout << "B::v" << std::endl; }
        f()  { std::cout << "B::f" << std::endl; }
    };
    
    void f()
    {
      A* a = new B;
      a->v();        // hier wird über die vtable B::v gefunden
      a->f();        // wie beim Destruktor wird hier nicht in der vtable gesucht,
                     // sondern einfach A::f aufgerufen
    }
    

    Tntnet



  • Und trotzdem knallt es bei mir den Speicher langsam voll. Mal 4kB, mal 8kB, mal 12kB, immer schöne Vielfache von 4096 Bytes 😕

    Habe eine Basisklasse, in der per CoCreateInstance ein Pointer auf ein XML-DOM-Dokument erzeugt wird, danach wird das Dokument vorstrukturiert und als Membervariable abgelegt.
    Die abgeleiteten Klassen stellen jeweils eine Klasse von XML-Dokumenten dar, die mit dem Pointer der Basisklasse weiterarbeiten.
    Der Pointer sollte im Destruktor der Basisklasse wieder freigegeben werden, allerdings verändert sich die Größe des Arbeitsspeichers nach dem Release()-Aufruf nicht.



  • Setz nen Breakpoint im Basusklassen-Destruktor und debugge deine Anwendung, dann siehst wann er in den Destruktor reinkommt.

    Ansonsten musst mal Code zeigen.



  • Er geht wie geplant in den Destruktor und führt auch Release() aus, um den per CoCreateInstance() erzeugten Interface-Pointer freizugeben. Nur der Speicher kommt nicht zurück.
    Es handelt sich um eine ISAPI-Extension, lasse ich den selben Vorgang im Rahmen einer Desktop-Anwendung laufen, wird der Speicher seltsamerweise korrekt freigegeben.


Anmelden zum Antworten