一个 std::vector 分配内存的位置在哪里?

37

考虑以下代码片段:

#include <vector>
using namespace std;

void sub(vector<int>& vec) {
    vec.push_back(5);
}

int main() {
    vector<int> vec(4,0);
    sub(vec);
    return 0;
}

假设"vec"在"sub"函数中没有足够的空间来存储5,它会在哪里分配新的内存?

在sub函数的堆栈帧中吗?如果是这样,那么5将在sub函数结束时被删除。但是主函数的堆栈帧不能增长,因为此时子函数的堆栈帧位于堆栈顶部。
std::vector会在堆上为其元素分配内存吗? 但是它如何释放该堆内存呢? 如果它是一个位于堆栈上的局部向量,则包括向量的函数的堆栈帧最终会被删除,而不通知向量它将被删除吗?


你可能想要查看STL分配器。 - pmdj
3
sub(vector<int>& vec) 改成 sub(vec) 会更易读 ;) - LihO
它在堆上分配内存。 std::vector 实现 - Arif_Khan
4个回答

45

std::vector是否在堆上为其元素分配内存?

是的。更准确地说,它根据您在构造函数中传递的分配器进行分配。您没有指定一个,所以您得到默认的分配器。默认情况下,这将是

但是它如何释放堆内存?

通过其析构函数当它超出作用域时。(请注意,指向超出作用域的向量的指针不会触发析构函数)。但如果您按值传递给sub,则会构造(稍后销毁)一个新副本。然后将5推回该副本,清理该副本,而main中的向量将不受影响。


5
我没有看到http://www.cplusplus.com/reference/std/memory/allocator/allocate/页面上提到默认分配在堆上的内容? - athos

21

STL中的所有容器都是使用模板参数化的,通常最后一个参数被称为AAllocator,默认为std::allocator<...>,其中...表示容器内存储的值的类型。

Allocator是一个用于提供内存并在此内存区域中构建/销毁元素的类。它可以从池或直接从堆中分配内存,具体取决于您构建分配器的方式。默认情况下,std::allocator<T>是一个简单的包装器,围绕着::operator new,因此将在堆上分配内存,正如您推断的那样。

内存是按需分配的,且至少在调用vector的析构函数时释放。C++11引入了shrink_to_fit以更早地释放内存。最后,当向量超过其当前容量时,会进行新的(更大)分配,对象被移动到其中,然后释放旧的分配。

与所有局部变量一样,在执行到达其声明的作用域的末尾时,析构函数被调用。因此,在函数退出之前,向量的析构函数被调用,只有在栈缩小且控制返回给调用者之后才会进行。


3
还要注意,你的向量(vec)本身就是一个对象。它驻留在堆栈中,当这个对象作用域结束时(在你的情况下是main的结尾),它会被销毁。元素的内存是在初始化该对象时分配的,并随着其销毁而释放,这是RAII习语的绝佳例子,因为元素的资源管理与向量对象的生命周期相关联。

0
因为你在子函数中传递了堆中向量的地址,所以它将分配在堆中。如果没有剩余空间,应该抛出异常。

4
堆上的向量与它分配内存在堆上之间绝对没有任何联系。 - Tom Knapen
这个向量不在“堆”上,无论它是什么。它在main的堆栈中。 - juanchopanza
无论您是在堆栈上还是在堆上分配向量, 默认实现始终会在堆上分配其内存。 - Tom Knapen
至少那是我想说的。考虑到我没有表达得够准确,这是我的错! - Stefan

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