35

考虑以下代码片段:

#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::vector 是否为其在堆上的元素分配内存?但是它是如何释放堆内存的呢?如果它是堆栈上的本地向量,那么包含该向量的函数的堆栈帧最终会被删除,而不会通知向量它将被删除?

4

4 回答 4

45

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

是的。或者更准确地说,它根据您在构建时传入的分配器进行分配。你没有指定一个,所以你得到了默认的分配器。默认情况下,这将是heap

但是它是如何释放堆内存的呢?

当它超出范围时通过它的析构函数。(请注意,指向超出范围的向量的指针不会触发析构函数)。但是,如果您按值传递给sub您,您将构建(然后破坏)一个新副本。然后 5 将被推回该副本,该副本将被清理,并且向量 inmain将保持不变。

于 2012-04-28T18:46:49.760 回答
21

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

Allocator是一个用于提供内存和构建/销毁此内存区域中的元素的类。它可以从池中分配内存,也可以直接从堆中分配内存,无论您从哪个构建分配器。默认情况下,它std::allocator<T>是一个简单的包装器::operator new,因此将按照您的推断在堆上分配内存。

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

与所有局部变量一样,析构函数在执行到它已声明到的范围的末尾时被调用。所以,在函数退出之前,向量析构函数被调用,只有在之后堆栈收缩并且控制权返回给调用者。

于 2012-04-28T18:54:40.717 回答
3

另请注意,您的向量 ( vec) 是对象本身。它驻留在堆栈上,当此对象超出范围(main在您的情况下为结束)时,它会被破坏。元素的内存在此对象的初始化期间分配并随着其销毁而释放,这是RAII习惯用法的一个可爱示例,因为元素的资源管理与向量对象的生命周期相关联。

于 2012-04-28T18:56:57.577 回答
0

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

于 2012-04-28T18:45:45.567 回答