vector初始化和容量控制应分清resize与reserve:reserve仅扩容不构造元素,resize则改变size并默认构造新元素;内存重分配会导致所有迭代器、指针、引用失效,循环中增删需用索引避免。

vector 初始化和容量控制容易误用 resize 和 reserve
很多人一上来就写 vec.resize(10),以为只是“预留空间”,结果发现元素全被默认构造了——这在不需要初始值的场景下纯属浪费。真正该用 reserve 的时候用了 resize,不仅多调构造函数,还可能触发不必要的析构(比如存的是非 trivial 类型)。
实操建议:
-
reserve(n)只改容量(capacity()),不改大小(size()),后续push_back才真正构造对象 -
resize(n)会把size()设为n,已存在元素保留,新增部分调默认构造;加第二个参数如resize(5, 42)则用 42 初始化新元素 - 如果确定要填满 n 个相同值,直接用初始化列表:
std::vector<int> vec(10, 42);</int>,比先reserve再循环push_back更高效
迭代器失效是 vector 最常踩的坑
只要发生内存重分配(比如 push_back 超过当前 capacity),所有指向该 vector 的迭代器、指针、引用全部失效。这不是“偶尔出错”,而是未定义行为——可能本地跑通,CI 上段错误,或者数据错乱。
常见错误现象:for (auto it = vec.begin(); it != vec.end(); ++it) 循环里调 vec.push_back(...),然后继续用 it —— 这时 it 已无效。
立即学习“C++免费学习笔记(深入)”;
实操建议:
- 循环中要增删元素?优先用索引
for (size_t i = 0; i ,删元素后不自增,增元素不影响索引有效性 - 必须用迭代器?删元素前先保存下一个位置:
it = vec.erase(it)(erase返回有效迭代器);增元素尽量放在循环外批量做 - 真需要频繁中间插入/删除?别硬扛
vector,换std::list或std::deque,它们的迭代器在增删时不全失效
vector 不是真正的容器,慎用
vector<bool></bool> 是 C++ 标准里唯一特化的容器,内部用位压缩存储,导致 operator[] 返回的不是 bool&,而是一个代理对象 std::vector<bool>::reference</bool>。这意味着你不能取它的地址,也不能绑定到 bool& 引用上。
典型报错:bool& b = vec[i]; 编译失败;auto ptr = &vec[i]; 报错 “cannot take address of bit-field”。
实操建议:
- 除非内存极度敏感且只读居多,否则直接用
std::vector<char></char>替代,它行为标准、调试友好、性能差距几乎可忽略 - 如果必须用
vector<bool></bool>,读写都走operator[],别试图取引用或指针;需要传参给函数时,显式转成bool:func(static_cast<bool>(vec[i]))</bool> - 注意
data()在vector<bool></bool>上不可用,别想拿原始内存块
移动语义能省掉深拷贝,但得主动触发
返回局部 vector 或传入临时对象时,编译器通常能自动应用移动(C++11 起),但有些写法会意外禁用它。比如写 return std::move(vec); 在返回局部变量时反而是画蛇添足,甚至阻止 RVO(返回值优化)。
性能影响明显:一个含百万 int 的 vector 拷贝要几毫秒,移动只是改三个指针。
实操建议:
- 函数返回局部
vector,直接return vec;,让编译器决定是 RVO 还是移动 - 接收参数时,想接管所有权就用右值引用:
void process(std::vector<int>&& data)</int>,然后内部用std::move(data)赋值给成员变量 - 避免对 const 对象调
std::move:const std::vector<int> v; ... f(std::move(v));</int>不会触发移动,还是走拷贝
vector 的边界其实不在语法,而在你是否清楚每次操作背后内存动了几下、迭代器还剩几个活口、代理对象藏在哪行代码里。这些地方不翻源码也得靠经验补全。










