请考虑以下代码段:
#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”没有空间将5存储在“sub”函数中,它在哪里分配新内存?
在子功能的堆栈框架中?在这种情况下,5将在子函数的末尾被删除。但是主函数的堆栈帧不能增长,因为子函数的堆栈帧在那一刻位于堆栈顶部。
std :: vector是否为堆上的元素分配内存?
但它如何释放堆内存呢?
如果它是堆栈上的局部向量,那么包含向量的函数的堆栈帧最终会被删除,而不会发信号通知它将被删除吗?
答案 0 :(得分:35)
std :: vector是否为堆上的元素分配内存?
是。或者更准确地说,它根据您在构造时传入的分配器进行分配。您没有指定一个,因此您获得默认分配器。默认情况下,这将是the heap。
但它如何释放堆内存?
当它超出范围时,通过其destructor。 (注意,超出范围的向量的指针不会触发析构函数)。但是如果你已经通过值sub
传递了一个新的副本,那么你构造(以后破坏)。然后将5推回到该副本,副本将被清理,main
中的向量将不受影响。
答案 1 :(得分:17)
STL中的所有容器都使用模板参数进行参数化,通常最后一个参数称为A
或Allocator
,默认为std::allocator<...>
,其中...
表示类型存储在容器中的值。
Allocator
是一个用于提供内存并构建/销毁此内存区域中元素的类。它可以从池中或直接从堆中分配内存,无论您从哪个构建分配器。默认情况下,std::allocator<T>
是::operator new
的简单包装器,因此会在您推断时在堆上分配内存。
内存按需分配,并且在调用vector
的析构函数时至少取消分配。 C ++ 11引入shrink_to_fit
来尽快释放内存。最后,当向量超出其当前容量时,将进行新的(更大的)分配,将对象移动到它,并释放旧的分配。
与所有局部变量一样,析构函数在执行时到达已声明的范围的末尾时被调用。因此,在退出函数之前,将调用向量析构函数,之后只有堆栈收缩并且控制权返回给调用者。
答案 2 :(得分:2)
另请注意,您的向量(vec
)本身就是对象。它驻留在堆栈上,当此对象超出范围(在您的情况下为main
的末尾)时,它将被破坏。元素的内存在此对象的初始化期间分配,并随其销毁而释放,这是RAII习语的一个可爱示例,因为元素的资源管理与向量对象的生命周期相关联。
答案 3 :(得分:0)
因为你在堆中给了sub的向量地址,所以它将在堆中分配。如果没有剩余空间,则应抛出异常。