
vector::push_back 触发扩容时,新容量怎么算?
STL 标准只规定 push_back 在需要扩容时必须保证摊还时间复杂度为 O(1),但**不强制要求倍增**;实际主流实现(libstdc++、libc++、MSVC STL)都采用「1.5 倍或 2 倍」增长策略,具体取决于实现:
- libstdc++(GCC):旧版本用
2 * old_capacity,GCC 13+ 默认改用old_capacity + old_capacity / 2(即 1.5 倍),避免内存浪费 - libc++(Clang):固定使用
2 * old_capacity - MSVC STL:也是
2 * old_capacity
这意味着你不能假设所有平台扩容后容量一定是翻倍——尤其在跨平台内存敏感场景下,capacity() 的增长路径可能不同。
为什么不用固定增量(比如每次 +10)而用倍增?
固定增量会导致 push_back 摊还复杂度退化为 O(n):插入 n 个元素需约 n²/10 次拷贝。倍增则把拷贝总次数压到 O(n) 级别。
举个例子:从空开始插入 16 个元素,按 2 倍扩容(0→1→2→4→8→16):
立即学习“C++免费学习笔记(深入)”;
拷贝次数 = 1 + 2 + 4 + 8 = 15
而按 +10 扩容(0→10→20):前 10 次无拷贝,第 11 次触发扩容,拷贝 10 个旧元素;后续插入不再拷贝——看似好?但插入 1000 个元素时,会触发约 100 次扩容,拷贝总量超 50000 次。
倍增的本质是用空间换均摊时间,且避免频繁小内存分配带来的堆管理开销。
reserve() 和 resize() 对扩容行为的影响
reserve(n) 只改变容量(capacity()),不改变大小(size()),也不会构造对象;resize(n) 改变大小,若 n > size() 则会默认构造新增元素,并在必要时自动扩容。
- 调用
reserve(100)后,push_back在第 101 次才可能触发下一次扩容 - 调用
resize(200)时,如果当前capacity() ,会先按实现策略分配新内存(比如扩到 256),再构造 200 个对象 -
resize(50)(当前 size=100)不会释放内存,capacity()不变——这是常见误区
手动控制扩容的坑:shrink_to_fit() 不一定真缩容
shrink_to_fit() 是非绑定请求,标准允许其实现“忽略”。libstdc++ 和 libc++ 通常会 realloc 并复制,但 MSVC STL 在某些版本中直接不响应。
更麻烦的是:即使缩容成功,也可能因内存对齐、分配器策略(如 small buffer optimization)导致 capacity() 仍大于 size()。
安全做法是:仅在明确内存压力大、且已 profiling 确认其有效时才用;否则优先靠 reserve() 预估,避免反复扩容缩容。
真正不可绕过的细节是:**vector 的迭代器/指针在任何扩容发生时全部失效**——哪怕只是 push_back 一次,只要触发了 reallocation,所有现存 &v[i]、v.begin() 都变成悬垂指针。










