web-dev-qa-db-ja.com

サブクラスへのポインターを削除すると、基本クラスのデストラクターが呼び出されますか?

フィールドの1つにヒープメモリ割り当てを使用するclass Aがあります。クラスAはインスタンス化され、別のクラス(class Bのポインターフィールドとして格納されます。

クラスBのオブジェクトの処理が完了したら、deleteを呼び出します。これはデストラクタと呼ばれますが、クラスAのデストラクタも呼び出しますか?

編集:

答えから、私はそれを取ります(間違っている場合は編集してください):

  1. BのインスタンスのdeleteはB ::〜B()を呼び出します;
  2. A::~A();を呼び出します
  3. A::~Ashould明示的にdelete Aオブジェクトのすべてのヒープに割り当てられたメンバー変数。
  4. 最後に、クラスBのインスタンスを格納するメモリブロックがヒープに返されます。-newが使用された場合、最初にヒープにメモリブロックを割り当て、次にすべてのデストラクタがオブジェクトをファイナライズするために呼び出され、オブジェクトが存在していたブロックがヒープに返されます。
159
Nick Bolton

Aのデストラクタは、そのライフタイムが終了すると実行されます。メモリを解放してデストラクタを実行する場合、ヒープに割り当てられている場合は削除する必要があります。スタックに割り当てられた場合、これは自動的に行われます(つまり、スコープから外れたとき。RAIIを参照)。クラスのメンバー(ポインターではなく、完全なメンバー)の場合、これは、包含オブジェクトが破棄されるときに発生します。

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

上記の例では、すべてのdeleteおよびdelete []が必要です。そして、私がそれを使用しなかった場合、削除は必要ありません(または実際に使用できます)。

auto_ptrunique_ptr、およびshared_ptrなどは、このライフタイム管理をはるかに簡単にするのに最適です。

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
179
Eclipse

Newによって割り当てられたポインターでdeleteを呼び出すと、ポイントされたオブジェクトのデストラクターが呼び出されます。

A * p = new A;

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

「デストラクタ」ではなく「デストラクタ」という名前です。

各クラスのデストラクタ内で、newで割り当てられた他のすべてのメンバー変数を削除する必要があります。

編集:明確にするために:

あなたが持っていると言う

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;
}

Bのインスタンスを割り当ててから削除するのは問題ありません。Bが内部的に割り当てたものもデストラクタで削除されるためです。

ただし、クラスCのインスタンスは、解放しないAのインスタンスを割り当てるため、メモリをリークします(この場合、Cにはデストラクタさえありません)。

22
Sebastian Mach

通常のポインタ(A*)がある場合、Aのデストラクタで明示的にdeleteを実行しない限り、デストラクタは呼び出されません(また、Bインスタンスのメモリも解放されません)。自動破棄が必要な場合は、auto_ptrなどのスマートポインターを確認してください。

5
sharptooth

Bのデストラクタで自分でAを削除する必要があります。

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;
    }
};

あなたがするとき:

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

デストラクタは、基本クラスに仮想キーワードがある場合にのみ呼び出されます。

次に、仮想デストラクタがない場合は、〜B()のみが呼び出されます。ただし、仮想デストラクタがあるため、最初に〜D()が呼び出され、次に〜B()が呼び出されます。

ヒープに割り当てられたBまたはDのメンバーは、明示的に削除しない限り割り当て解除されません。そして、それらを削除するとデストラクタも呼び出されます。

2
Brian R. Bondy

クラスのデストラクタが呼び出されないのはなぜだろうと思っていました。その理由は、そのクラスの定義を含めるのを忘れていたためです(#include "class.h")。 「クラスA」のような宣言しかありませんでした。コンパイラーはこれに満足しており、「削除」と呼びます。

1
Harri Luoma

いいえ。ポインターは削除されます。 Bのデストラクタで明示的にAで削除を呼び出す必要があります。

0
RvdK

クラスAのオブジェクトのデストラクタは、そのオブジェクトに対して削除が呼び出された場合にのみ呼び出されます。クラスBのデストラクタでそのポインタを必ず削除してください。

オブジェクトでdeleteが呼び出されたときに何が起こるかについての詳細は、以下を参照してください: http://www.parashift.com/c++-faq-lite/freestore-mgmt.html#faq-16.9

0
Kris Kumler

いいえ、クラスAのデストラクタを呼び出しません。明示的に呼び出して(PoweRoyのように)、行 'delete ptr;'を削除する必要があります。比較する例では...

  #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

あなたのようなものがあります

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

その後delete b;を呼び出すと、何も起こらず、メモリリークが発生します。 delete b->a;を覚えようとするのは良い解決策ではありませんが、他にもいくつかあります。

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

これは、aを削除するBのデストラクタです。 (aが0の場合、その削除は何もしません。aが0ではないが、新しいメモリを指し示していない場合、ヒープが破損します。)

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

この方法では、ポインタとしてではなく、auto_ptr <>(shared_ptr <>でも同様に機能します、または他のスマートポインタ)があり、bが存在すると自動的に削除されます。

これらの方法のいずれかがうまく機能し、両方を使用しました。

0
David Thornley