考虑以下代码片段:
#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,它在哪里分配新内存?
在子函数的栈帧中?在这种情况下,5将在子函数的末尾被删除。但是主函数的栈帧不能增长,因为子函数的栈帧在那一刻位于堆栈之上。
std::向量是否为其堆上的元素分配内存?但是它如何释放堆内存?如果它是堆栈上的本地向量,则包含该向量的函数的栈帧最终被删除,而不会向向量发出将被删除的信号?
std::向量是否为堆上的元素分配内存?
是的。或者更准确地说,它根据您在构建时传入的分配器进行分配。您没有指定一个,因此您获得默认分配器。默认情况下,这将是堆。
但是它如何释放堆内存呢?
当它超出作用域时通过它的析构函数。(请注意,指向超出作用域的向量的指针不会触发析构函数)。但是如果您将值传递给sub
,您将构建(然后销毁)一个新副本。5将被推回到该副本上,副本将被清理,main
中的向量将保持不变。
STL中的所有容器都使用模板参数进行参数化,通常最后一个参数称为A
或Allocator
,默认为std::allocator
Allocator
是一个类,用于提供内存和构建/销毁此内存区域中的元素。它可以从池中或直接从堆中分配内存,无论您从何处构建分配器。默认情况下,std::allocator
内存是按需分配的,并且至少在调用向量
的析构函数时被释放。C 11引入了shrink_to_fit
来更快地释放内存。最后,当向量超出其当前容量时,进行新的(更大的)分配,将对象移动到其中,并释放旧的分配。
和所有局部变量一样,析构函数在执行到它被声明的范围的末尾时被调用。因此,在函数退出之前,向量析构函数被调用,只有在之后堆栈收缩并控制返回给调用者。
另请注意,您的向量(vec
)是对象本身。它驻留在堆栈上,当该对象超出范围时(在您的情况下是main
的末尾),它会被破坏。元素的内存在该对象的初始化期间分配并随其销毁而释放,这是RAII习惯用法的一个可爱示例,因为元素的资源管理与向量对象的生命周期相关联。