it-swarm.com.de

Ruft delete auf einem Zeiger auf eine Unterklasse den Basisklassendestruktor auf?

Ich habe einen class A, Der eine Heap-Speicherzuordnung für eines seiner Felder verwendet. Klasse A wird instanziiert und als Zeigerfeld in einer anderen Klasse gespeichert (class B).

Wenn ich mit einem Objekt der Klasse B fertig bin, rufe ich delete auf, von dem ich annehme, dass es den Destruktor aufruft ... Aber nennt dies auch den Destruktor der Klasse A?

Bearbeiten:

Aus den Antworten entnehme ich das (bitte korrigieren, falls nicht korrekt):

  1. delete einer Instanz von B ruft B :: ~ B () auf;
  2. welches A::~A(); aufruft
  3. A::~Asollte explizit delete alle vom Heap zugewiesenen Elementvariablen des A-Objekts;
  4. Schließlich wird der Speicherblock, in dem diese Instanz der Klasse B gespeichert ist, in den Heap zurückgegeben. Wenn new verwendet wurde, hat er zuerst einen Speicherblock im Heap zugewiesen und dann Konstruktoren aufgerufen, um ihn zu initialisieren, nachdem alle Destruktoren dies getan haben wurde aufgerufen, um das Objekt abzuschließen. Der Block, in dem sich das Objekt befand, wird auf den Heap zurückgegeben.
161
Nick Bolton

Der Destruktor von A wird ausgeführt, wenn seine Lebensdauer abgelaufen ist. Wenn Sie möchten, dass der Speicher freigegeben und der Destruktor ausgeführt wird, müssen Sie ihn löschen, wenn er auf dem Heap zugeordnet wurde. Wenn es auf dem Stack zugewiesen wurde, geschieht dies automatisch (d. H. Wenn es den Gültigkeitsbereich verlässt; siehe RAII). Wenn es sich um ein Mitglied einer Klasse handelt (kein Zeiger, sondern ein Vollmitglied), geschieht dies, wenn das enthaltende Objekt zerstört wird.

class A
{
    char *someHeapMemory;
public:
    A() : someHeapMemory(new char[1000]) {}
    ~A() { delete[] someHeapMemory; }
};

class B
{
    A* APtr;
public:
    B() : APtr(new A()) {}
    ~B() { delete APtr; }
};

class C
{
    A Amember;
public:
    C() : Amember() {}
    ~C() {} // A is freed / destructed automatically.
};

int main()
{
    B* BPtr = new B();
    delete BPtr; // Calls ~B() which calls ~A() 
    C *CPtr = new C();
    delete CPtr;
    B b;
    C c;
} // b and c are freed/destructed automatically

Im obigen Beispiel ist jedes Löschen und Löschen von [] erforderlich. Und es ist kein Löschen erforderlich (oder kann tatsächlich verwendet werden), wenn ich es nicht verwendet habe.

auto_ptr, unique_ptr und shared_ptr etc ... sind großartig, um dieses lebenslange Management zu vereinfachen:

class A
{
    shared_array<char> someHeapMemory;
public:
    A() : someHeapMemory(new char[1000]) {}
    ~A() { } // someHeapMemory is delete[]d automatically
};

class B
{
    shared_ptr<A> APtr;
public:
    B() : APtr(new A()) {}
    ~B() {  } // APtr is deleted automatically
};

int main()
{
    shared_ptr<B> BPtr = new B();
} // BPtr is deleted automatically
180
Eclipse

Wenn Sie delete für einen von new zugewiesenen Zeiger aufrufen, wird der Destruktor des Objekts aufgerufen, auf das verwiesen wird.

A * p = new A;

delete p;    // A:~A() called for you on obkect pointed to by p
30
anon

Es heißt "Destruktor", nicht "Dekonstruktor".

Innerhalb des Destruktors jeder Klasse müssen Sie alle anderen Mitgliedsvariablen löschen, die mit new belegt wurden.

bearbeiten: Zur Verdeutlichung:

Sagen Sie, Sie haben

struct A {}

class B {
    A *a;
public:
    B () : a (new A) {}
    ~B() { delete a; }
};

class C {
    A *a;
public:
    C () : a (new A) {}        
};

int main () {
    delete new B;
    delete new C;
}

Das Zuweisen einer Instanz von B und das anschließende Löschen sind fehlerfrei, da das, was B intern zuweist, auch im Destruktor gelöscht wird.

Bei Instanzen der Klasse C tritt jedoch ein Speicherverlust auf, da sie eine Instanz von A zuweisen, die sie nicht freigibt (in diesem Fall hat C nicht einmal einen Destruktor).

22
Sebastian Mach

Wenn Sie einen normalen Zeiger (A*) Haben, wird der Destruktor nicht aufgerufen (und der Speicher für die Instanz A wird ebenfalls nicht freigegeben), es sei denn, Sie tun delete explizit im Destruktor von B. Wenn Sie automatische Zerstörung möchten, schauen Sie sich intelligente Zeiger wie auto_ptr An.

5
sharptooth

Sie sollten A selbst im Destruktor von B löschen.

4
corné
class B
{
public:
    B()
    {
       p = new int[1024];  
    }
    virtual ~B()
    {
        cout<<"B destructor"<<endl;
        //p will not be deleted EVER unless you do it manually.
    }
    int *p;
};


class D : public B
{
public:
    virtual ~D()
    {
        cout<<"D destructor"<<endl;
    }
};

Wenn Sie das tun:

B *pD = new D();
delete pD;

Der Destruktor wird nur aufgerufen, wenn Ihre Basisklasse das virtuelle Schlüsselwort hat.

Wenn Sie dann keinen virtuellen Destruktor hätten, würde nur ~ B () aufgerufen. Da Sie jedoch einen virtuellen Destruktor haben, wird zuerst ~ D () und dann ~ B () aufgerufen.

Auf dem Heap zugewiesene Mitglieder von B oder D werden nur freigegeben, wenn Sie sie explizit löschen. Wenn Sie sie löschen, wird auch ihr Destruktor aufgerufen.

2
Brian R. Bondy

Ich fragte mich, warum der Destruktor meiner Klasse nicht aufgerufen wurde. Der Grund war, dass ich vergessen hatte, die Definition dieser Klasse aufzunehmen (#include "class.h"). Ich hatte nur eine Erklärung wie "Klasse A"; und der Compiler war damit zufrieden und ließ mich "delete" nennen.

1
Harri Luoma

Nein, der Zeiger wird gelöscht. Sie sollten den Löschvorgang für A im Destruktor von B explizit aufrufen.

0
RvdK

Der Destruktor für das Objekt der Klasse A wird nur aufgerufen, wenn für dieses Objekt delete aufgerufen wird. Stellen Sie sicher, dass Sie diesen Zeiger im Destruktor der Klasse B löschen.

Weitere Informationen darüber, was passiert, wenn delete für ein Objekt aufgerufen wird, finden Sie unter: http://www.parashift.com/c++-faq-lite/freestore-mgmt.html#faq-16.9

0
Kris Kumler

nein, es wird keinen Destruktor für Klasse A aufrufen. Sie sollten ihn explizit aufrufen (wie PoweRoy sagte) und die Zeile 'delete ptr' löschen. in beispiel zu vergleichen ...

  #include <iostream>

  class A
  {
     public:
        A(){};
        ~A();
  };

  A::~A()
  {
     std::cout << "Destructor of A" << std::endl;
  }

  class B
  {
     public:
        B(){ptr = new A();};
        ~B();
     private:
        A* ptr;
  };

  B::~B()
  {
     delete ptr;
     std::cout << "Destructor of B" << std::endl;
  }

  int main()
  {
     B* b = new B();
     delete b;
     return 0;
  }
0

Sie haben so etwas wie

class B
{
   A * a;
}
B * b = new B;
b->a = new A;

Wenn Sie dann delete b; Aufrufen, passiert mit a nichts und Sie haben einen Speicherverlust. Der Versuch, sich an delete b->a; Zu erinnern, ist keine gute Lösung, aber es gibt ein paar andere.

B::~B() {delete a;}

Dies ist ein Destruktor für B, der a löscht. (Wenn a den Wert 0 hat, hat das Löschen keine Auswirkung. Wenn a nicht den Wert 0 hat, aber nicht auf den Arbeitsspeicher von new verweist, tritt eine Heap-Beschädigung auf.)

auto_ptr<A> a;
...
b->a.reset(new A);

Auf diese Weise haben Sie kein a als Zeiger, sondern ein auto_ptr <> (shared_ptr <> oder andere intelligente Zeiger), und es wird automatisch gelöscht, wenn b ist.

Beides funktioniert gut, und ich habe beides verwendet.

0
David Thornley