
直接说结论:用 reserve() 预分配内存,但别和 resize() 搞混——它只改容量不改大小,也不构造元素。
为什么 reserve() 能提升性能
vector 在插入过程中可能多次触发扩容:每次容量不够时,会申请新内存、拷贝旧元素、销毁旧对象。频繁扩容带来 O(n²) 的拷贝开销和额外的构造/析构调用。
reserve() 提前锁定足够大的连续内存块,后续 push_back() 或 emplace_back() 就不会触发重新分配,直到容量再次不足。
- 适用于「知道最终元素个数」的场景,比如读取文件行数、解析固定长度数据包
- 对含非平凡构造函数的对象(如
std::String、自定义类)效果更明显 - 不改变
size(),operator[]和迭代器仍只能访问已存在的元素
reserve() 和 resize() 的关键区别
这是最常踩的坑:两个函数名字像,行为完全不同。
立即学习“C++免费学习笔记(深入)”;
-
reserve(n):确保capacity() >= n;不新增元素,不调用任何构造函数 -
resize(n):强制让size() == n;若n > size(),会默认构造新元素(调用默认构造函数) - 调用
reserve(100)后,size()仍是 0,vec[0]是未定义行为 - 调用
resize(100)后,size()变成 100,所有新元素已构造完成
实际怎么用才不翻车
预分配不是“越多越好”,也不是“越早越好”。要结合使用模式判断:
- 如果后续全是
push_back(),且能预估总数(比如循环 1e6 次),就vec.reserve(expected_count) - 如果后续要随机写入(如
vec[i] = x),必须先用resize()或配合reserve() + push_back()构造出位置 - 避免在循环内反复调用
reserve(),它本身有开销;宁可略高估,也不要频繁重分配 - 注意:
reserve()不会释放已有内存,想缩容得用shrink_to_fit()(但它是非强制的)
示例:
std::vector lines; lines.reserve(1000); // 预分配,但 lines.size() 还是 0 for (int i = 0; i < 1000; ++i) { lines.push_back(read_line()); // 此时不会 realloc,且每个 string 独立构造 }
容易被忽略的细节
reserve 对移动语义友好的类型(如 std::unique_ptr、std::string)收益稳定;但对 trivial 类型(如 int)影响较小,因为拷贝成本低——真正瓶颈往往在构造/析构逻辑上。
另外,某些 STL 实现(如 libstdc++)在 reserve(0) 或极小值时可能不释放内存,而 clear() + shrink_to_fit() 才能真正归零容量。
预分配这事,本质是用空间换时间,但前提是「你真的知道要多少」——盲目 reserve(1