vector扩容在size()等于capacity()时触发,如push_back、insert或resize超容时;reserve仅预分配不构造;扩容导致迭代器失效且开销大;vector是特例,不遵循常规扩容规则。

vector 的扩容不是“按需分配一点”,而是每次触发就重新申请一块更大的连续内存,把旧数据搬过去再释放旧空间——这个过程会导致所有迭代器、指针和引用失效,且开销不小。
vector 什么时候会扩容
扩容只在插入操作导致 size() == capacity() 时发生,典型场景包括:
-
push_back()插入新元素时容量已满 -
insert()在非尾部位置插入,且插入后总元素数超过当前容量 -
resize(n)将大小设为大于当前capacity()的值
注意:reserve(n) 不会改变 size(),也不会触发构造;它只是预分配空间,不调用元素的构造函数。而 resize(n) 会调整 size(),必要时还会默认构造新元素。
扩容因子到底是多少
没有标准规定,完全取决于 STL 实现:
立即学习“C++免费学习笔记(深入)”;
-
libstdc++(GCC 默认):通常用 2 倍,比如容量从 4 → 8 → 16 -
libc++(Clang 默认):常用 1.5 倍,比如 4 → 6 → 9 → 13 - MSVC STL:早期版本用 1.5,新版趋向 2 倍,但行为可能随版本微调
你可以用简单循环实测:
std::vector<int> v;
for (int i = 0; i < 20; ++i) {
v.push_back(i);
if (v.capacity() != v.size()) // 避免刚初始化时 capacity==0 的干扰
std::cout << "size=" << v.size() << ", cap=" << v.capacity() << "\n";
}
输出序列就能反推出你当前编译器用的是哪种策略。
为什么不能靠扩容来“省事”
频繁扩容不只是慢,还隐含三重代价:
- 内存碎片风险:多次小规模扩容后释放的旧内存块可能无法被后续大块分配复用
-
移动/拷贝开销:每个已有元素都要调用移动构造或拷贝构造,对复杂类型(如
std::string、自定义类)尤其明显 -
迭代器失效不可逆:一旦扩容,所有指向该 vector 的
iterator、const_iterator、data()返回的指针、甚至&v[0]都变成悬垂指针
所以工程中,如果你知道最终大概要存多少个元素(比如解析一个已知长度的 JSON 数组),直接 v.reserve(expected_count) 是最便宜的预防手段。
vector 是个特例
它不是真正的容器,而是一个位域代理类(bit proxy)。它的 operator[] 返回的是临时 std::vector<bool>::reference</bool> 对象,不是 bool&;它也不满足 “连续存储” 这一 vector 核心契约;data() 甚至不可用。因此它不遵循上述任何扩容逻辑——它压根就没有传统意义上的 capacity 或 data 指针。别把它当普通 vector 用,尤其别传给期望 bool* 的 C 接口。


















