我需要对C ++内存分配做一些澄清,我只是做一个例子
假设我已经创建了一个类A,它包含两个容器:一个hash_map和一个std :: vector,如下所示:
class Example{
// methods to add stuff to containers
//...
std::hash_map<std::string,int> map;
std::vector<std::string> vec;
}
如果我然后使用new运算符在堆上创建示例对象:
Example* ex = new Example();
并为每个容器添加一千个条目,我添加的条目也将位于堆上吗?如果是,那么如果我这样做会有什么不同:
class Example{
// methods to add stuff to containers
//...
std::hash_map<std::string,int>* map;
std::vector<std::string>* vec;
}
然后Example* ex = new Example();
答案 0 :(得分:5)
无论存储hash_map
或vector
的位置,它们包含的数据都将始终位于堆中。
int main() {
hash_map<T> table;
}
table
在堆栈中。 table
包含的数据位于堆上。
int main() {
hash_map<T> *table = new hash_map<T>();
}
table
是堆栈上存在的指针。 *table
是堆上存在的hash_map
。 *table
包含的数据仍在堆中。
hash_map<T> table;
int main() {
...
}
table
不在堆或堆栈中。数据table
指向的数据仍在堆中。
答案 1 :(得分:3)
两个容器中的数据项总是在堆中; 有std :: hash_map映射和。之间的区别 std :: hash_map * map是第一种情况,你的Example对象保存实际的对象映射(特别是,当销毁Example对象时会自动销毁),而在第二种情况下,你的Example对象只保存指向对象图(可能在其他地方创建/销毁)。
答案 2 :(得分:2)
new Example();
这个语句总是意味着在堆上分配一个Example对象并返回指向该对象的指针。
Example ex;
是在堆栈上分配单个Example对象的方法。
您描述的差异在Example对象的内容中。在第一个实例中,对象直接保存stl向量和hash_map的实例(它们由对象构造并随之释放)
在第二个实例中,对象保存指针容器,并且放在这些指针上的内容保持打开状态。
在任何情况下,vector和hash_map都会使用堆来存储您插入的数据,但是它们会隐藏您的详细信息和管理。 (你可以提供分配器来搞乱默认值)
高级注意:
Example ex;
当在函数/方法的范围内时,会在堆栈上分配对象。范围退出时释放对象。在命名空间或全局范围内使用时,它将在数据段中分配对象,并在程序终止时释放该对象。
答案 3 :(得分:1)
在这两种情况下,您的对象都将在堆上实例化。 new
运算符执行此操作。
你的两个例子之间的区别在于,在第一个例子中,没有使用*
作为两个成员,当你调用new Example()
时,它们被隐式构造为你对象的一部分(在记忆中,你的对象布局将包含hash_map和大小为sizeof(hash_map)
和sizeof(vector)
的矢量。)
在第二种情况下,当您将成员声明为指针时,内存中的对象布局将只包含2 sizeof(void*)
- 基本上是指针大小,所有指针的大小都相同,无论它们指向何种类型。这也意味着,当您使用new Example()
实例化您的课程时,您的成员默认为nullptr
,因此您必须使用new hash_map
和new vector
明确初始化每个成员为了使用它们。
对于堆栈分配,如果要在堆栈上分配Example
类的实例,则在函数中使用
Example foo;
而不是
Example* foo = new Example();
这将在堆栈上分配foo并在函数返回时自动销毁它。