C ++堆/堆栈澄清

时间:2015-04-05 15:16:02

标签: c++ initialization stack heap

我需要对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();

4 个答案:

答案 0 :(得分:5)

无论存储hash_mapvector的位置,它们包含的数据都将始终位于堆中。

示例1

int main() {
    hash_map<T> table;
}

table在堆栈中。 table包含的数据位于堆上。

示例2

int main() {
    hash_map<T> *table = new hash_map<T>();
}

table是堆栈上存在的指针。 *table是堆上存在的hash_map*table包含的数据仍在堆中。

示例3

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_mapnew vector明确初始化每个成员为了使用它们。

对于堆栈分配,如果要在堆栈上分配Example类的实例,则在函数中使用

Example foo;

而不是

Example* foo = new Example();

这将在堆栈上分配foo并在函数返回时自动销毁它。