170

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

クラス B のオブジェクトを使い終わったら、 を呼び出しますdelete。これは、デストラクタを呼び出すと想定しています...しかし、これはクラス A のデストラクタも呼び出すのでしょうか?

編集:

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

  1. deleteB のインスタンスの呼び出し B::~B();
  2. 呼び出すA::~A();
  3. A::~A deleteA オブジェクトのすべてのヒープ割り当てメンバー変数を明示的に指定する必要があります。
  4. 最後に、クラス B のインスタンスを格納しているメモリ ブロックがヒープに返されます。new使用されると、最初にメモリ ブロックがヒープに割り当てられ、次にコンストラクタが呼び出されて初期化され、すべてのデストラクタが呼び出されてオブジェクトがファイナライズされます。オブジェクトが存在したブロックはヒープに戻されます。
4

11 に答える 11

188

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
于 2009-03-24T14:32:33.683 に答える
32

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

A * p = new A;

delete p;    // A:~A() called for you on obkect pointed to by p
于 2009-03-24T14:36:11.647 に答える
22

「デコンストラクタ」ではなく「デストラクタ」と呼ばれます。

各クラスのデストラクタ内で、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 にはデストラクタさえありません)。

于 2009-03-24T14:32:22.797 に答える
5

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

于 2009-03-24T14:34:39.437 に答える
4

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

于 2009-03-24T14:33:55.210 に答える
4
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;

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

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

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

于 2009-03-24T14:34:03.323 に答える
1

あなたは次のようなものを持っています

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

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

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

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

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

この方法では、ポインターとして a を使用するのではなく、auto_ptr<> (shared_ptr<> やその他のスマート ポインターも使用できます) を使用し、b の場合は自動的に削除されます。

これらの方法はどちらもうまく機能し、私は両方を使用しました。

于 2009-03-24T15:00:40.077 に答える
0

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

于 2009-03-24T14:32:13.077 に答える
0

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

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

于 2009-03-24T14:35:15.533 に答える
0

いいえ、クラス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;
  }
于 2009-03-24T14:50:35.077 に答える