当一个类在堆上实例化时。是否所有成员变量也分配在堆上或其他地方。那么在堆上显式分配成员变量有什么好处吗?
struct abc {
std::vector<int> vec;
}
int main() {
abc* ptr = new abc(); //the "class" is on the heap but where is vec?
ptr->vec.push_back(42); //where will the 42 be stored?
return 0;
}
这会有什么不同
struct abc {
std::vector<int>* vec_ptr;
abc() { vec_ptr = nev std::vector<int>(); }
int main() {
abc* ptr = new abc();
ptr->vec->push_back(42);
}
答案 0 :(得分:4)
非静态数据成员存储在它们所属的对象(类实例)中。
如果您将对象创建为具有自动存储持续时间的本地对象,则其成员为 在里面。如果动态分配对象,它们就在其中。 如果使用一些完全不同的分配方案分配对象,则其成员仍将位于其中的任何位置。对象的成员是该对象的部分。
请注意,此处的vector
实例位于您的结构中,但vector
本身为您推送到其中的项目管理自己的动态存储空间。因此,abc
实例在通常的免费商店中动态分配,其中包含vector
成员,42
位于由vector
实例管理的单独动态分配中。
例如,说vector是这样实现的:
template <typename T, typename Allocator = std::allocator<T>>
class vector {
T *data_ = nullptr;
size_t capacity_ = 0;
size_t used_ = 0;
// ...
};
然后capacity_
和used_
都是矢量对象的一部分。 data_
指针也是对象的一部分,但由向量管理的内存(指向由data_
)不是。
::operator new
管理的资源。那里可能有任何东西,这是另一个实现细节。答案 1 :(得分:0)
您的问题可以简化。考虑:
int main()
{
std::vector<int> v;
v.push_back(42);
}
“42
存储在哪里?”
在此示例中,v
是一个自动变量,因此它存储在本地作用域的存储(通常是堆栈)中。但请注意v
具有固定的小尺寸 - 它只是处理程序对象。包含元素的实际内存由向量的内部逻辑单独分配,使用指定的分配器(在本例中为std::allocator
),后者从免费存储中获取所有内存。
类的所有(非静态)数据成员构成该类的数据类型的一部分并占用空间 - 这基本上与哑C struct
相同。但是,大多数C ++库类的神奇之处在于它们的数据成员只是微小的指针,并且所有有效负载数据都是单独分配的,并由类的内部逻辑进行管理。
因此,当你创建一个包含大量矢量成员的类时,类本身仍然不会很大。该类的任何实例都将在任何地方(无论是自动,动态,静态)完整地分配,但要注意每个成员对象将单独请求额外的单独内存来完成其工作。
答案 2 :(得分:0)
将new
ed对象视为连续分配。创建abc
的新实例会创建最小大小为sizeof(abc)
的分配。
当您通过new
创建时,系统不会单独分配该类的成员。举例说明:new
不会为每个成员,子成员调用new
。因此,数据成员存储在由new
创建的连续分配中,这是一个单独的分配。
在vector
的情况下,向量内部对其元素使用动态分配 - 这是使用单独的分配完成的。这个分配是在vector的实现中完成的。
因此成员确实驻留在堆上,但它们作为abc
实例的一部分存在,并且该实例使用一个分配,不包括数据成员创建的任何分配。
那么在堆上显式分配成员变量有什么好处吗?
是肯定的。您可能选择这样做的原因有很多。考虑问题的背景:你应该赞成将你的成员声明为值,直到有充分理由不(details here)。当你需要将你的成员声明为堆分配时,总是使用适当的容器(例如自动指针,共享指针),因为这样可以节省大量的精力,时间和复杂性。