我的问题主要是理论上的。假设我们有一个班级
class A{
private:
int * a;
int b;
private:
A(){
a = new int[100];
b = 100;
}
~A(){
delete [] a;
}
}
据我所知,如果我们动态创建类型A的对象(A * a = new A()
),该对象的内存将在堆中分配,如果我使用(A a
),它将在堆栈上创建{ {1}}。在堆栈上创建对象的情况下,变量(A a)
将在堆上分配,如果我们在堆内存上为对象a
分配了对象,则会在堆栈上分配。第一个问题让我确定:我是对的吗?
第二个问题是将所有类成员存储在堆内存或堆栈内存中会更有效吗?
b
当我说效率时,我的意思是关于类成员的所有数据都将在堆或堆栈的内存中彼此靠近存储(实际上我不确定它们是否正确存储在彼此附近)。
答案 0 :(得分:5)
首先,C ++中没有堆或堆栈。相反,我们有自动存储持续时间和动态存储时间。具有自动存储持续时间的对象是范围对象。当它超出范围时,它会自动清理。另一方面,具有动态存储持续时间的对象不受其范围的约束。它的生命周期仅在程序明确结束时结束(通常这意味着调用delete
)。
现在在A
中,您有一个存储了自动存储时间{0}的对象,以及一个具有动态存储时长的b
。这意味着a
将存在于b
实例所在的任何地方。 A
也存在于a
实例中,但它指向的内存将驻留在内存中,但我们不知道在哪里。当实例被销毁时,A
将被自动清除,但b
将需要在析构函数中进行特殊处理,否则内存将泄漏。您可以将其视为
a
就效率提到Some programmer dude而言,你不应该真的担心这一点。你应该使用你所擅长的类型。一旦你完成并运行,你就可以对其进行剖析以找到瓶颈的位置。如果由于使用指针而看到太多缓存未命中,那么您可以尝试将数据本地化到类本身。
我还想提一下,如果你发现自己在写 A
+------+ +----------+
| a->+---| 100 ints |
| b | +----------+
+------+
,那么你应该考虑使用some_type* name = new/new[]
或std:unique_ptr<some_type>/std:unique_ptr<some_type[]>
。
答案 1 :(得分:1)
不,你不完全正确。
a
和b
是对象中的变量。
它们都扩展了班级的大小 - 至少大小为sizeof(int*)
。
根据构造对象的方式,这个变量的内存在堆栈或堆上分配,如上所述:
new A/int/etc
在堆上分配内存
A/int/etc. var
在堆栈上分配内存
你想念的是你在构造函数中分配的数据
a = new int[100];
不是您的类对象的一部分。这是一些外部数据。在您的类对象中,您只有int*
成员(大小为4-8字节,具体取决于体系结构)指向此数据。
答案 2 :(得分:0)
首先,成员原始指针(例如MyClass
)的缺点是强制#include
声明MyClass
的标题。这可能导致编译速度慢。要解决此问题,您可以使用具有前向声明的智能指针。
第二个问题是将所有类成员存储在堆内存或堆栈内存中会更有效吗?
通常最好只在必要时使用指针。您通常应该将成员声明为类中的值。它将是本地的,错误的机会更少,分配更少,最终可能出错的东西更少,编译器总是可以知道它在指定的偏移量处,所以...它有助于优化和二进制减少水平。