フィールドの1つにヒープメモリ割り当てを使用するclass A
があります。クラスAはインスタンス化され、別のクラス(class B
のポインターフィールドとして格納されます。
クラスBのオブジェクトの処理が完了したら、delete
を呼び出します。これはデストラクタと呼ばれますが、クラスAのデストラクタも呼び出しますか?
答えから、私はそれを取ります(間違っている場合は編集してください):
delete
はB ::〜B()を呼び出します;A::~A();
を呼び出しますA::~A
should明示的にdelete
Aオブジェクトのすべてのヒープに割り当てられたメンバー変数。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_ptr
、unique_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
Newによって割り当てられたポインターでdeleteを呼び出すと、ポイントされたオブジェクトのデストラクターが呼び出されます。
A * p = new A;
delete p; // A:~A() called for you on obkect pointed to by p
「デストラクタ」ではなく「デストラクタ」という名前です。
各クラスのデストラクタ内で、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にはデストラクタさえありません)。
通常のポインタ(A*
)がある場合、A
のデストラクタで明示的にdelete
を実行しない限り、デストラクタは呼び出されません(また、B
インスタンスのメモリも解放されません)。自動破棄が必要な場合は、auto_ptr
などのスマートポインターを確認してください。
Bのデストラクタで自分でAを削除する必要があります。
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のメンバーは、明示的に削除しない限り割り当て解除されません。そして、それらを削除するとデストラクタも呼び出されます。
クラスのデストラクタが呼び出されないのはなぜだろうと思っていました。その理由は、そのクラスの定義を含めるのを忘れていたためです(#include "class.h")。 「クラスA」のような宣言しかありませんでした。コンパイラーはこれに満足しており、「削除」と呼びます。
いいえ。ポインターは削除されます。 Bのデストラクタで明示的にAで削除を呼び出す必要があります。
クラスAのオブジェクトのデストラクタは、そのオブジェクトに対して削除が呼び出された場合にのみ呼び出されます。クラスBのデストラクタでそのポインタを必ず削除してください。
オブジェクトでdeleteが呼び出されたときに何が起こるかについての詳細は、以下を参照してください: http://www.parashift.com/c++-faq-lite/freestore-mgmt.html#faq-16.9
いいえ、クラス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;
}
あなたのようなものがあります
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が存在すると自動的に削除されます。
これらの方法のいずれかがうまく機能し、両方を使用しました。