【问题标题】:Class members and explicit stack/heap allocation类成员和显式堆栈/堆分配
【发布时间】:2012-06-05 21:17:02
【问题描述】:

假设我们有 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 分配在堆上。这里会发生什么?这两部分是否在内存中分开?如果我从析构函数中删除了“删除 m_D”并且 myC1 超出范围,那么在堆上为 m_D 分配的空间是否会出现内存泄漏?

如果有任何教程/文章详细介绍了这一点,我希望有一个链接。

【问题讨论】:

    标签: c++ memory memory-management heap-memory stack-memory


    【解决方案1】:

    我认为您混淆了“堆栈/堆分配”和“自动变量”。

    自动变量会在脱离上下文时自动销毁。

    堆栈分配是内存分配在执行堆栈上的事实。而栈上分配的变量是自动变量。

    另外,成员是自动变量,其析构函数在其所有者被销毁时被调用。在指针的情况下,它们被销毁但不是底层对象,您必须显式调用 delete。为确保底层对象被销毁,您必须使用智能或唯一指针。

    换句话说:必须调用 delete 的变量/成员不是自动变量。

    最后,类的成员分配在其所有者的同一内存段上。

    在你的代码中:

    • 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在栈上,是一个自动变量,指向m_D的指针也在栈上,但不是m_D指向的对象,它是由new on分配的堆。
    • 案例 4: 与案例 3 相同,但 myC2 在堆上并且不是自动的。所以你必须删除myC2(这将删除m_D)。

    【讨论】:

      【解决方案2】:

      案例 1:“堆栈”上的所有内容(自动存储)。当您退出范围时,资源会被释放。

      案例2:myA2在“堆”上,m_B也是,你只需要担心释放myA2占用的资源。当myA2 存在时,它的m_B 将自动销毁。

      案例 3:myC1 在堆栈上,它的 m_D 指向堆上的 D,但 C 析构函数负责删除它,因此 myC1 超出范围,所有动态分配的资源都被清除。

      案例4:myC2动态分配,必须删除它才能释放它占用的资源。删除它将调用它的构造函数,而构造函数又会处理它的m_D,如案例 3。

      我不确定文章,我相信周围有很多。但我建议阅读一些good C++ books

      【讨论】:

        【解决方案3】:

        你的对象是一块有组织的记忆。对象不会在堆栈上分配它的成员,它只是由它的成员组成。

        情况2:整个对象存在于堆中,这意味着它的所有成员都在堆中。

        案例3:整个对象存在于栈中。诀窍在于myC1 的成员不是D 类实例,而是pointer-to-BmyC1物理上 成员。所以myC1 的成员位于堆栈上并指向位于堆中的一些D 实例。

        【讨论】:

          猜你喜欢
          • 2011-02-18
          • 2012-06-26
          • 2017-08-12
          • 2018-09-09
          • 2018-03-27
          • 1970-01-01
          • 2011-10-06
          • 2012-10-01
          相关资源
          最近更新 更多