当向量被分配时,它们使用堆栈还是堆内存?

229

以下所有语句都是正确的吗?

vector<Type> vect; //allocates vect on stack and each of the Type (using std::allocator) also will be on the stack

vector<Type> *vect = new vector<Type>; //allocates vect on heap and each of the Type will be allocated on stack

vector<Type*> vect; //vect will be on stack and Type* will be on heap. 

vector 或任何其他 STL 容器中,Type 的内存分配是如何实现的?


1
可能是类成员和显式堆栈/堆分配的重复问题。 - underscore_d
5个回答

324
vector<Type> vect;

将会在堆栈上分配`vector`,也就是头部信息,但元素会在自由存储区(“堆”)上。
vector<Type> *vect = new vector<Type>;

将所有内容分配到自由存储器上(除了在堆栈上的 vect 指针)。
vector<Type*> vect;

将在堆栈上分配vector和一堆指针,但这些指针指向的位置取决于您如何使用它们(例如,您可以将元素0指向堆栈,将元素1指向自由存储区)。

3
我会尽力进行翻译,但请注意我的能力范围,以下是需要翻译的内容:但是我遇到了这样一种情况:在第二个声明中,当 Type 变得很大时,我得到了一个分段错误。我原以为这是因为 Type 被分配在栈上。 - Phelodas
5
@Phelodas:如果没有看到你的代码,就无法评估。请提出一个新的问题。 - Fred Foo
2
关于vector<Type> vect;,由于元素在堆上,头信息在栈上,当头信息从内存中移除时(例如函数返回),元素内存会怎么处理?它们会和头信息一起被回收吗?如果不会,这会导致内存泄漏吗? - flyrain
4
@flyrain:向量自我清理。请了解一下RAII - Fred Foo
1
@flyrain:那应该可以。请发布一个带有更多细节的新问题。如果你在这里发布链接,我可能会看一下。 - Fred Foo
显示剩余3条评论

43
vector<Type> vect; //allocates vect on stack and each of the Type (using std::allocator) also will be on the stack
不,vect 会在栈上分配空间,但其内部用于存储元素的数组会在堆上分配。这些元素将驻留在该数组中。
vector<Type> *vect = new vector<Type>; //allocates vect on heap and each of the Type will be allocated on stack
不行。和上面一样,只是 vector 类也会在堆上。
vector<Type*> vect; //vect will be on stack and Type* will be on heap. 
vect将会在栈上,其元素(指向Type的指针)将会在堆上,而你无法确定指针所指向的Type的位置。它们可能在栈上、堆上、全局数据中,或者根本不存在(即NULL指针)。

顺便说一下,实现方式确实可以完全将某些向量(通常是小型向量)存储在栈上。虽然我不知道有这样的实现,但确实可以做到。


2
这对所有STL容器都适用吗,还是仅适用于std :: vector? - MTV
@MTV 所有具有 Allocator 模板参数的容器(即非 std::array - Caleth

25
假设实现确实具有堆栈和堆(标准C++不要求这些东西),那么唯一正确的陈述是最后一个。
vector<Type> vect;
//allocates vect on stack and each of the Type (using std::allocator) also will be on the stack

这是正确的,除了最后一部分(Type 不会在栈上)。想象一下:

  void foo(vector<Type>& vec) {
     // Can't be on stack - how would the stack "expand"
     // to make the extra space required between main and foo?
     vec.push_back(Type());
  }

  int main() {
    vector<Type> bar;
    foo(bar);
  }

同样地:
 vector<Type> *vect = new vector<Type>; //allocates vect on heap and each of the Type will be allocated on stack

除了最后一部分外都是正确的,这里给出一个类似的反例:

  void foo(vector<Type> *vec) {
     // Can't be on stack - how would the stack "expand"
     // to make the extra space required between main and foo?
     vec->push_back(Type());
  }

  int main() {
    vector<Type> *bar = new vector<Type>;
    foo(bar);
  }

针对:

vector<Type*> vect; //vect will be on stack and Type* will be on heap. 

这是正确的,但需要注意的是Type*指针将在堆上,但它们所指向的Type实例不一定在堆上。

  int main() {
    vector<Type*> bar;
    Type foo;
    bar.push_back(&foo);
  }

在什么样的情况下你不会使用栈?我理解你说标准并不要求使用它,但实际上,在什么情况下你会没有栈呢? - Nerdtron
3
据我所知,一些小型微控制器上的调用栈只能存储最后一次调用时的程序计数器(PC),以便进行RET操作。为此,您的编译器可能会选择将“自动存储”(对于非递归函数)放置在与执行流程关系很小/没有关系的固定位置上。整个程序可以被压平是完全可行的。即使是递归情况下,您也可以采用“每个函数一个栈”的策略或者为自动变量和返回地址使用单独的栈,这使得“栈”这个短语有点毫无意义。 - Flexo
你可以使用基于堆的分配方式来处理所有的事情,并拥有一个“清理栈”来管理自动存储(可能还包括delete)。 - Flexo

4

vector有一个内部的allocator,负责为vector元素heap分配/释放内存。因此,无论如何创建一个vector,它的元素总是在heap上分配的。至于vector的元数据,它取决于你创建它的方式。


3
只有这个声明是真实的:
vector <Type*> vect; //vect will be on stack and Type* will be on heap.

Type*指针存储在堆上,因为指针的数量可以动态改变。

vect在此情况下分配在栈上,因为您将其定义为本地栈变量。


4
Type*并不表示堆分配,仅仅表示一个Type对象的指针。话虽如此,这个vector确实将指针存储在堆上。int a = 5; int *ptr_to_a = &a; vector<int*> vec; vec.push_back(ptr_to_a);(见jpalecek所述的答案) - optimus_prime
1
"Type并不表示堆分配" - 同意,我没有声称相反的。 "向量确实在堆上存储指针" - 也同意,这正是我所说的“Type指针在堆上分配”的意思。 - Alexei Khlebnikov
这个答案完全是错误的。Type* 没有任何意义,它可以在堆上或者栈上。 - Enerccio
@Enerccio,给定代码 vector <Type*> vect;Type* 指针存储在堆上。这些指针存储在堆上不是因为它们是指针,而是因为它们存储在向量中。 - Alexei Khlebnikov
@AlexeiKhlebnikov 标准并没有规定数据必须在堆上分配,它可以使用alloca进行分配,但绝大多数情况下会在堆上分配内存。 - Tom McLean

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接