类成员和显式堆栈/堆分配

时间:2012-05-31 15:28:27

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

我们说我们有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:在堆栈上外部分配,B在堆栈内部分配

A myA1;

案例2:在堆上外部分配,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&#​​39;从析构函数和myC1超出范围,堆上为m_D分配的空间是否存在内存泄漏?

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

3 个答案:

答案 0 :(得分:39)

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

离开上下文时,

自动变量会自动销毁。

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

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

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

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

在你的代码中:

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

所以:

  • 案例1:一切都在堆栈上并自动进行(即:自动销毁)。
  • 案例2: myA2在堆上而非自动(您必须delete myA2)。其成员m_B2是一个自动变量,在myA2被销毁时将被销毁。此外,由于myA2位于堆上,m_B与类的任何成员一样,也在堆的同一内存空间中。
  • 案例3: myC1在堆栈上并且是一个自动变量,指向m_D的指针也在堆栈上,但不是{{{{1}指向的对象1}}由堆上的new分配。
  • 案例4:与案例3相同,但m_D在堆上并且不是自动的。因此,您必须删除myC2(将删除myC2)。

答案 1 :(得分:6)

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

案例2:myA2位于“堆”上,因此它是m_B,您只需担心释放myA2占用的资源。当m_BmyA2时,myC1会被自动销毁。

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

案例4:m_D动态分配,必须删除它才能释放它所占用的资源。删除它将调用它的构造函数,而构造函数将依次处理{{1}},如案例3所示。

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

答案 2 :(得分:2)

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

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

案例3:堆栈上存在整个对象。诀窍是D类实例不是myC1的成员,但是指向B的指针 成员{{1} }}。所以myC1的成员位于堆栈上并指向堆中的某个myC1实例。