我们说我们有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'从析构函数和myC1超出范围,堆上为m_D分配的空间是否存在内存泄漏?
如果有任何教程/文章详细介绍,我会喜欢链接。
答案 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分配的,它将在堆上。所以:
myA2
在堆上而非自动(您必须delete myA2
)。其成员m_B2
是一个自动变量,在myA2
被销毁时将被销毁。此外,由于myA2
位于堆上,m_B
与类的任何成员一样,也在堆的同一内存空间中。myC1
在堆栈上并且是一个自动变量,指向m_D
的指针也在堆栈上,但不是{{{{1}指向的对象1}}由堆上的new分配。m_D
在堆上并且不是自动的。因此,您必须删除myC2
(将删除myC2
)。答案 1 :(得分:6)
案例1:“堆栈”上的所有内容(自动存储)。退出范围时会释放资源。
案例2:myA2
位于“堆”上,因此它是m_B
,您只需担心释放myA2
占用的资源。当m_B
为myA2
时,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
实例。