次の4つのクラスがあるとします。
class A
{
public:
A(void) : m_B()
{
}
private:
B m_B;
}
class B
{
public:
B(void)
{
m_i = 1;
}
private:
int m_i;
}
class C
{
public:
C(void)
{
m_D = new D();
}
~C(void)
{
delete m_D;
}
private:
D *m_D;
}
class D
{
public:
D(void)
{
m_i = 1;
}
private:
int m_i;
}
4つのケースがあるとしましょう:
ケース1:Aはスタックに外部的に割り当てられ、Bはスタックに内部的に割り当てられます。
A myA1;
ケース2:Aはヒープに外部割り当てされ、Bはスタックに内部割り当てされます
A *myA2 = new A();
ケース3:Cはスタックに外部的に割り当てられ、Dはヒープに内部的に割り当てられます
C myC1;
ケース4:Cがヒープに外部的に割り当てられ、Dが内部的にヒープに割り当てられます
C *myC2 = new C();
これらのケースのそれぞれで何が起こっていますか?たとえば、ケース2では、ポインタmyA2がスタックに割り当てられ、Aオブジェクトがヒープに存在することを理解していますが、m_B属性についてはどうでしょうか。オブジェクトがヒープスペースに存在しても意味がなく、その属性がスコープから外れるため、ヒープ上のスペースも割り当てられていると想定しています。これが当てはまる場合、それは外部ヒープ割り当てが内部スタック割り当てをオーバーライドすることを意味しますか?
ケース3では、myC1がスタックに割り当てられますが、m_Dはヒープに割り当てられます。そこで何が起こるの? 2つの部分はメモリ間で分割されていますか?デストラクタから「deletem_D」を削除し、myC1がスコープ外になった場合、m_Dのヒープに割り当てられたスペースのメモリリークが発生しますか?
これを詳細に説明しているチュートリアル/記事があれば、リンクが欲しいです。
「スタック/ヒープ割り当て」と「自動変数」を混同していると思います。
自動変数は、コンテキストから抜けると自動的に破棄されます。
スタック割り当ては、メモリが実行スタックに割り当てられるという事実です。そして、スタックに割り当てられた変数は自動変数です。
また、メンバーは自動変数ですは、その所有者が破棄されたときにデストラクタが呼び出されます。ポインタの場合、ポインタは破棄されますが、基になるオブジェクトは破棄されません。明示的にdeleteを呼び出す必要があります。基になるオブジェクトが確実に破棄されるようにするには、スマートポインターまたは一意のポインターを使用する必要があります。
別の言い方をすれば、deleteを呼び出さなければならない変数/メンバーは自動変数ではありません。
最後に、クラスのメンバーは、その所有者と同じメモリセグメントに割り当てられます。
あなたのコードでは:
A.m_B
は自動変数です。 Aがスタック上にある場合、Bも同様であり、Aがヒープ上にある場合、Bも同様です。B.m_i
およびD.m_iは自動変数であり、所有者の同じメモリセグメントに割り当てられますC.m_D
は自動変数ですが、タイプDのポイントされたオブジェクトは自動変数ではありません。基になるオブジェクトを削除するには、ポインターでdeleteを明示的に呼び出す必要があります。したがって、ポインタC.m_Dは同じメモリセグメントに割り当てられますが、基になるオブジェクトには割り当てられません。それは明らかにnewによって割り当てられ、ヒープ上にあります。そう:
myA2
はヒープ上にあり、自動ではありません(delete myA2
にする必要があります)。そのメンバーm_B2
は、myA2
が破棄されると破棄される自動変数です。また、myA2
はヒープ上にあるため、クラスの他のメンバーと同様に、m_B
もヒープ内の同じメモリ空間にあります。myC1
はスタック上にあり、自動変数です。m_D
へのポインターもスタック上にありますが、m_D
が指すオブジェクトではありません。これは、ヒープ上のnewによって割り当てられます。myC2
はヒープ上にあり、自動ではありません。したがって、myC2
を削除する必要があります(これにより、m_D
が削除されます)。ケース1:「スタック」(自動ストレージ)上のすべて。スコープを終了すると、リソースが解放されます。
ケース2:myA2
は「ヒープ」上にあるため、m_B
もそうであり、myA2
によって使用されているリソースを解放することのみを心配する必要があります。 m_B
の場合、myA2
は自動的に破棄されます。
ケース3:myC1
はスタック上にあり、m_D
はヒープ上のD
を指しますが、C
デストラクタが削除するため、myC1
はスコープ外になり、動的に割り当てられたすべてのリソースがクリアされます。
ケース4:動的に割り当てられたmyC2
、それに割り当てられたリソースを解放するために削除する必要があります。それを削除すると、コンストラクターが呼び出され、ケース3のように、コンストラクターがm_D
を処理します。
記事についてはよくわかりませんが、周りにはたくさんあると思います。しかし、私はいくつかを読むことをお勧めします 良いC++の本
あなたのオブジェクトは組織化された記憶の一部です。オブジェクトはそのメンバーをスタックに割り当てません。それは単にそのメンバーで構成されます。
ケース2:オブジェクト全体がヒープ内に存在します。これは、オブジェクトのすべてのメンバーがヒープ内にあることを意味します。
ケース3:全体オブジェクトがスタックに存在します。秘訣は、myC1
のメンバーであるのはD
クラスインスタンスではなく、pointer-to-Bは物理的にmyC1
のメンバーであるということです。したがって、myC1
のメンバーはスタック上にあり、ヒープ内にあるD
インスタンスを指します。