vector 的扩容时机由 size() == capacity() 决定;此时按实现策略(如 libstdc++ 1.5 倍、msvc 2 倍)重新分配内存,保证摊还 o(1);resize(n) 仅当 n > capacity() 时才扩容。

vector 的扩容时机由什么决定?
不是每次 push_back 都触发扩容,而是当 size() == capacity() 时才 realloc 内存。标准库通常按 1.5 倍或 2 倍增长(GCC libstdc++ 用 1.5,MSVC 用 2),具体取决于实现,但都保证摊还时间复杂度为 O(1)。
常见误判:以为 resize(n) 一定会扩容——其实它只改变 size,若 n > capacity() 才真正分配新内存;若 n ,则截断并调用元素析构函数。
-
reserve(n)只影响capacity,不改变size,也不初始化元素 -
resize(n)改变size,必要时也扩容,并对新增元素默认构造或值初始化 - 直接访问
vec[i](i ≥size())是未定义行为,哪怕i
如何避免频繁扩容带来的性能抖动?
如果已知最终规模(比如读取文件前先统计行数),应优先调用 reserve()。否则在循环中反复 push_back 可能引发多次内存分配+拷贝(尤其是存储非 trivial 类型时)。
示例对比:
立即学习“C++免费学习笔记(深入)”;
// 不推荐:可能触发 4–5 次扩容(假设初始 cap=1,倍增) vector<string> v; for (int i = 0; i < 1000; ++i) v.push_back(to_string(i)); // 推荐:一次分配到位 vector<string> v; v.reserve(1000); for (int i = 0; i < 1000; ++i) v.push_back(to_string(i));
- 对 POD 类型(如
int),扩容开销主要是 memcpy;对含构造/析构逻辑的类型(如string),还要额外调用移动或拷贝构造函数 -
shrink_to_fit()是非强制请求,实际是否缩容由实现决定,且会引发一次重新分配
capacity 为 0 时 push_back 会发生什么?
首次 push_back 必然触发分配。初始 capacity 是实现定义的(常见为 0 或 1),但所有标准库都会确保至少分配能容纳 1 个元素的空间。
验证方式:
vector<int> v; cout << v.capacity() << endl; // 可能输出 0(如 libc++)或 1(如 libstdc++) v.push_back(42); cout << v.capacity() << endl; // 至少为 1,通常为 1 或更大(如 2)
- 不要依赖初始
capacity值,它不是标准要求项 - 用
empty()判断是否为空,而不是capacity() == 0 - 移动一个 vector 后,源对象的
capacity()可能变为 0(取决于是否执行了“掏空”优化)
自定义类里用 vector 要注意什么?
vector 成员变量本身不参与基类/派生类的内存布局计算,但它的动态内存是独立堆分配的。重点在于:析构顺序、异常安全、移动语义是否正确传递。
- 若类有自定义析构函数,确保 vector 成员能自动清理(它本来就会)
- 在移动构造函数中,应使用
std::move(other.vec),而非手动 swap 或 copy - 若 vector 存储的是裸指针(如
vector<int></int>),扩容不会释放原指针指向的内存,需自行管理 - 多线程环境下,不同 vector 对象之间可并发操作;但同一 vector 的读写不能并发(除非只读)
真正容易被忽略的是:vector 的迭代器失效规则——插入(push_back、insert)、删除(erase、pop_back)都可能使已有迭代器/引用/指针失效,尤其扩容后所有迭代器全失效。别在循环体里一边 push_back 一边用 begin() 迭代。










