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

如果有任何教程/文章详细介绍了这个,我会喜欢一个链接。

4

3 回答 3

58

I think that you are confusing "stack/heap allocation" and "automatic variable".

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

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

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

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

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

在你的代码中:

  • A.m_B是一个自动变量。如果 A 在堆栈上,那么 B 也是,如果 A 在堆上,那么 B 也是。
  • B.m_i和 D.m_i 是自动变量,将分配在其所有者的同一内存段上
  • 指针 是自动变量,但 D 类型的C.m_D指向对象不是,您必须在指针上显式调用 delete 才能删除底层对象。因此,指针 C.m_D 分配在同一内存段上,而不是底层对象。它显然是由 new 分配的,并且将在堆上。

所以:

  • 案例1:一切都在堆栈上并且是自动的(即:自动销毁)。
  • 案例2: myA2在堆上而不是自动的(你必须delete myA2)。它的成员m_B2是一个自动变量,当被销毁时将被myA2销毁。此外,由于myA2在堆上,因此m_B与类的任何成员一样,也位于堆的同一内存空间中。
  • 情况3: myC1在栈上,是一个自动变量,指向的指针m_D也在栈上,但不是m_D堆上new分配的指向的对象。
  • 案例 4:与案例 3相同,但myC2在堆上且不是自动的。所以你必须删除myC2(这将删除m_D)。
于 2012-05-31T16:03:54.873 回答
9

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

情况2:myA2在“堆”上,它也是m_B,你只需要担心释放被占用的资源myA2。它m_B会在 is 时自动销毁myA2

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

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

I am not sure about articles, I am sure there are plenty around. But I suggest reading some good C++ books

于 2012-05-31T15:37:51.787 回答
2

Your object is a piece of organised memory. Object does not allocate it's members on the stack, it just consists of it's members.

Case 2: the whole object exists in the heap, this means that all it's members lie in the heap.

Case 3: the whole object exists on the stack. The trick is that it's not D class instance who is member of myC1, but pointer-to-B is physically member of myC1. So member of myC1 lies on stack and points to some D instance that lies in the heap.

于 2012-05-31T15:42:35.627 回答