reserve() 能省掉 realloc 和 memcpy,因其提前分配足够内存,使后续 push_back 只需 placement new 构造元素;它只改变 capacity 而不改变 size,也不初始化元素。

reserve() 为什么能省掉 realloc 和 memcpy
vector 在 push_back 时空间不够,会分配新内存、把旧元素逐个 move 或 copy 过去、再释放旧内存——这三步加起来开销不小,尤其存的是大对象或非 trivial 类型。调用 reserve() 提前划好地盘,后续插入就只做构造(placement new),跳过搬数据环节。
注意:reserve() 只影响容量(capacity()),不改变大小(size())。它不会初始化元素,也不会触发任何构造函数。
- 常见错误:误以为
v.reserve(100)后v[0]就能访问——实际会越界,因为size()还是 0 - 正确姿势:先
reserve(),再用push_back()或emplace_back()增加元素;若需默认构造填满,该用resize() - 如果已知最终元素数且不会动态增删,
reserve()+emplace_back()是最轻量的组合
什么时候调用 reserve() 才真有效
不是所有场景都值得 reserve。它只在「可预估数量」+「连续插入」+「避免多次扩容」这三个条件同时满足时才明显收益。
典型有效场景:读文件行、解析 JSON 数组、批量网络响应解包、循环生成固定规模数据。
立即学习“C++免费学习笔记(深入)”;
- 反例:边查数据库边插入,每次只来一条,
reserve()没法预估总数,纯属白忙 - 反例:插入后频繁
erase()或insert()中间位置,预留空间很快被碎片化,反而浪费内存 - 小技巧:若总数不确定但有上限(比如“最多 1000 条”),按上限
reserve()仍比默认 2 倍扩容(如 1→2→4→8…)更可控
reserve() 的参数陷阱和 size/capacity 混淆
reserve(n) 的参数是「最小容量」,不是「保证容量」。实际分配可能更大(取决于 allocator 和实现),但绝不会更小。最容易出错的是把 size() 和 capacity() 当成一回事。
常见错误现象:v.size() == 50,却调 v.reserve(50)——毫无作用,因为当前 capacity 已经 ≥ 50;真正需要的是 v.reserve(100) 才可能避免下次 push 触发扩容。
- 安全写法:总是基于预期最大元素数调用,例如
v.reserve(expected_max_count) - 调试建议:插入前打印
v.capacity()和v.size(),确认 reserve 是否生效 - 注意:
shrink_to_fit()不是reserve()的逆操作,它只是请求缩小,不保证成功,也不影响已有元素
不同 STL 实现下 reserve() 的行为差异
libc++、libstdc++、MSVC STL 对 reserve 后的 capacity 增长策略不同,但都遵守标准:不减少现有 capacity,且保证至少为参数值。不过,它们对“超额分配”的倾向不一样。
比如 MSVC STL 在 reserve(100) 后常返回 capacity() == 100;而 libstdc++ 可能向上取整到最近的 2 的幂(如 128),这是为了减少后续插入时再次扩容的概率。
- 性能影响:libstdc++ 的“多给一点”策略在持续追加时更省事,但内存占用略高;MSVC 更精准,适合内存敏感场景
- 兼容性提醒:别依赖
capacity()的具体数值做逻辑判断,只用于调试或估算 - 跨平台项目里,若发现某处 reserve 后插入速度波动大,优先检查是否混用了
resize()和reserve()导致意外构造/析构
reserve 的核心价值不在“快”,而在“确定性”——它把不可控的隐式扩容,变成一次可控的显式分配。真正难的不是调用它,而是准确预估那个数字,以及意识到有些场景根本没法预估。











