vector扩容仅在size()≥capacity()时触发,push_back()在容量足够时不重新分配内存;reserve()预分配容量,shrink_to_fit()请求释放多余空间,但均不保证跨平台行为一致。

vector 的扩容不是每次 push_back 都触发
真正决定要不要扩容的,是当前容量 capacity() 是否够用。只要 size() < capacity(),push_back() 就只是拷贝/移动元素到已有内存末尾,不涉及分配、复制、释放老内存——这是高频操作能快的关键。
常见错误现象:std::vector<int> v; for (int i = 0; i < 1000; ++i) v.push_back(i); 看似简单,但可能触发约 10 次内存重分配(具体次数取决于实现,通常按 1.5× 或 2× 增长)。每次扩容都要:申请新内存 → 逐个移动旧元素 → 释放旧内存 → 更新指针。
- 使用场景:频繁增删尾部且数量不可预估时,
push_back()是首选;但若已知最终规模(比如读配置后初始化),优先调用reserve(n) -
reserve(n)只改变容量,不改变大小(size()仍为 0);resize(n)则会改变大小,必要时填充默认值或调用构造函数 - 不同 STL 实现增长策略不同:libstdc++(GCC)用 1.5×,MSVC 用 2×,但都保证摊还时间复杂度为 O(1)
迭代器失效只发生在扩容那一刻
很多人以为“只要改 vector 就会让迭代器失效”,其实不然。只有当插入/删除导致内部缓冲区地址变化时,所有指向该 vector 的迭代器、指针、引用才失效。没扩容时,push_back()、pop_back()、operator[] 全部安全。
典型踩坑:auto it = v.begin(); v.push_back(x); *it = 42; —— 如果这次 push_back 触发了扩容,it 就成了悬空指针,行为未定义。
立即学习“C++免费学习笔记(深入)”;
- 避免方式:在可能扩容前,用索引代替迭代器(
v[i]),或提前reserve()锁定内存位置 -
insert()和erase()在中间位置操作时,即使没扩容也会使“被擦除位置及之后”的迭代器失效;尾部erase(v.end()-1)不影响其他迭代器 - 调试技巧:开启 libstdc++ 的 debug mode(编译加
-D_GLIBCXX_DEBUG)可捕获大部分迭代器误用
移动语义让 vector<BigObject> 不再可怕
旧观念里,把大对象塞进 vector 总担心深拷贝开销。C++11 后,只要类型支持移动构造(如含 std::unique_ptr、std::string 的类),push_back(std::move(obj)) 或直接 emplace_back(...) 就能绕过拷贝,只转移资源所有权。
错误写法:v.push_back(MyClass(a, b)); —— 构造临时对象,再拷贝进 vector;正确写法:v.emplace_back(a, b); 直接在 vector 内存里构造。
-
emplace_back转发参数,调用元素类型的构造函数;push_back接收已存在对象(左值或右值) - 如果元素类型没有移动构造函数(比如手动禁用了,或含非移动成员),
emplace_back仍可能触发拷贝;此时需检查类定义 - 性能影响:对 POD 类型(如
int、double),两者无差别;对含动态内存的类,移动比拷贝快一个数量级
clear() 不释放内存,shrink_to_fit() 才真“缩容”
clear() 只把 size() 归零,所有元素调用析构函数,但底层缓冲区还在,capacity() 不变。下次再 push_back,只要不超过原容量,就复用这块内存。
常见误解:清空 vector 后内存占用没降下来,以为有内存泄漏。其实这是故意设计——避免反复分配释放,提升后续使用的效率。
- 需要真正释放内存时,调用
v.shrink_to_fit();,它向实现“请求”释放多余空间(注意:不是强制,标准允许忽略) - 可靠缩容写法(兼容旧标准):
std::vector<T>(v).swap(v);—— 创建临时 vector 并交换,确保释放 - 兼容性注意:
shrink_to_fit()C++11 引入,但早期 GCC 版本(如 4.8)对std::string有效,对vector可能无效;建议实测v.capacity()变化
最常被忽略的一点:扩容策略和缩容行为完全由实现决定,不能跨平台假设增长倍数或 shrink_to_fit() 是否生效;生产环境如有严格内存要求,必须用 valgrind 或 ASan 配合实际数据压测验证。








