39

次のように 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 つの部分はメモリ間で分割されていますか? デストラクタから 'delete m_D' を削除し、myC1 が範囲外になった場合、m_D のヒープに割り当てられたスペースでメモリ リークが発生しますか?

これを詳しく説明しているチュートリアル/記事があれば、リンクが大好きです。

4

3 に答える 3

58

「スタック/ヒープ割り当て」と「自動変数」を混同していると思います。

自動変数は、コンテキストから外れると自動的に破棄されます。

スタック割り当ては、メモリが実行スタックに割り当てられるという事実です。また、スタック上に確保される変数は自動変数です。

また、メンバーは、所有者が破棄されたときにデストラクタが呼び出される自動変数です。ポインターの場合、それらは破棄されますが、基になるオブジェクトではなく、明示的に削除を呼び出す必要があります。基になるオブジェクトが確実に破棄されるようにするには、スマート ポインターまたは一意のポインターを使用する必要があります。

別の言い方をすれば、削除を呼び出さなければならない変数/メンバーは、自動変数ではありません。

最後に、クラスのメンバーは、その所有者の同じメモリ セグメントに割り当てられます。

あなたのコードで:

  • A.m_Bは自動変数です。A がスタック上にある場合は B も、A がヒープ上にある場合は B も同様です。
  • B.m_iおよび D.m_i は自動変数であり、所有者の同じメモリ セグメントに割り当てられます。
  • ポインター C.m_Dは自動変数ですが、型 D の指定されたオブジェクトはそうではありません。基になるオブジェクトを削除するには、ポインターに対して明示的に delete を呼び出す必要があります。そのため、ポインタ C.m_D は同じメモリ セグメントに割り当てられますが、基になるオブジェクトには割り当てられません。new によって明確に割り当てられ、ヒープ上に配置されます。

そう:

  • ケース 1:すべてがスタック上にあり、自動です (つまり、自動的に破棄されます)。
  • ケース 2: myA2ヒープ上にあり、自動ではありません (する必要がありますdelete myA2)。そのメンバーm_B2は、が破棄されるときに破棄される自動変数ですmyA2。また、myA2はヒープ上にあるためm_B、クラスのメンバーと同様に、ヒープも同じメモリ空間にあります。
  • ケース 3: myC1スタック上にあり、自動変数です。ポインタもスタック上にありますが、ヒープ上で new によって割り当てられm_Dたオブジェクトが指すオブジェクトではありません。m_D
  • ケース 4: ケース 3と同じmyC2ですが、ヒープ上にあり、自動ではありません。したがって、削除する必要がありますmyC2(削除されますm_D)。
于 2012-05-31T16:03:54.873 に答える
9

ケース1:「スタック」(自動ストレージ)上のすべて。スコープを終了すると、リソースが解放されます。

ケース2:myA2は「ヒープ」にあるので、そうであり、m_Bによって占有されているリソースを解放することだけを心配する必要がありますmyA2。のm_B場合、自動的に破棄されますmyA2

ケース3:myC1スタック上にあり、ヒープ上のm_Daを指していますが、デストラクタが削除を処理するため、スコープ外になると、動的に割り当てられたすべてのリソースがクリアされます。DCmyC1

ケース4:myC2動的に割り当てられ、それによって使用されたリソースを解放するには、削除する必要があります。削除すると、コンストラクターが呼び出さm_Dれ、ケース3のようにコンストラクターが処理します。

記事についてはよくわかりませんが、周りにはたくさんあると思います。しかし、私はいくつかの良いC++の本を読むことをお勧めします

于 2012-05-31T15:37:51.787 に答える
2

オブジェクトは、整理された記憶の一部です。オブジェクトはスタックにメンバーを割り当てず、メンバーだけで構成されます。

ケース 2: オブジェクト全体がヒープに存在します。これは、オブジェクトのすべてのメンバーがヒープにあることを意味します。

ケース 3:オブジェクト全体がスタックに存在します。トリックは、のDメンバーであるクラスインスタンスではmyC1なく、B へのポインター物理的にのメンバーであることmyC1です。したがって、メンバーはスタック上にあり、ヒープ内にmyC1あるインスタンスを指します。D

于 2012-05-31T15:42:35.627 に答える