std::vector 构造需区分括号与花括号:vector v; 为空,v(5) 创建5个0,v{1,2,3} 初始化3个元素;erase后必须用返回迭代器继续遍历,或用erase-remove惯用法。

直接说结论:std::vector 是 C++ 标准库中最常用、最值得优先掌握的序列容器,但它不是“万能数组替代品”——它的性能特征、迭代器失效规则和内存行为必须明确理解,否则容易在扩容、erase、多线程等场景踩坑。
vector 的构造和初始化有哪些安全写法?
常见错误是用 vector 误以为创建了空容器,其实它构造了含 10 个默认值(0)的 vector;更隐蔽的是 vector,这创建的是含单个元素 10 的 vector。
-
vector—— 空容器,v; v.size() == 0 -
vector—— 含 5 个v(5); int{}(即 5 个 0) -
vector—— 初始化列表,含 3 个元素v{1,2,3}; -
vector—— 迭代器区间构造,注意传入有效范围v(other.begin(), other.end()); - 避免
vector这种拷贝初始化(C++17 后通常无差别,但语义不如直接列表初始化清晰)v = {1,2,3};
push_back 和 emplace_back 到底该用哪个?
两者都尾插,但语义和开销不同:push_back 接收值或 const 引用,可能触发一次拷贝或移动;emplace_back 在容器内直接构造对象,绕过临时对象。
struct Point {
int x, y;
Point(int x_, int y_) : x(x_), y(y_) {}
};
vector v;
v.push_back(Point(1, 2)); // 构造临时 Point,再移动/拷贝进 vector
v.emplace_back(1, 2); // 直接在 vector 尾部内存上调用 Point(int,int) 构造
只要类型支持就位构造(即有匹配的构造函数),且参数不涉及隐式转换歧义,emplace_back 更优。但对 int、string 等简单类型,差异可忽略。
立即学习“C++免费学习笔记(深入)”;
erase 迭代器失效后怎么安全遍历删除?
vector::erase 删除元素后,被删位置及之后所有迭代器、引用、指针全部失效——这是最常被忽视的陷阱。错误写法:for (auto it = v.begin(); it != v.end(); ++it) if (*it == x) v.erase(it);,这会导致 it 失效后继续自增,UB(未定义行为)。
- 正确做法:用
erase返回的迭代器继续遍历:for (auto it = v.begin(); it != v.end(); ) if (*it == x) it = v.erase(it); else ++it; - 批量删除推荐 erase–remove 惯用法:
v.erase(remove(v.begin(), v.end(), x), v.end()); - 若需按条件删除,用
remove_if:v.erase(remove_if(v.begin(), v.end(), [](int a){ return a
capacity 和 size 不一致时,reserve 和 shrink_to_fit 怎么选?
size() 是当前元素个数,capacity() 是已分配但未必使用的内存容量。扩容(如 push_back 触发)时,capacity 通常按 1.5× 或 2× 增长,导致内存浪费。
-
v.reserve(n):预分配至少n容量,避免后续多次扩容;只增不减,不改变size -
v.shrink_to_fit():请求释放多余容量,但标准不保证一定成功(底层可能仍保留部分内存),C++11 起可用 - 高频插入前调
reserve可显著提升性能;大量删除后调shrink_to_fit可降低内存占用,但要注意它可能引发一次重新分配(移动所有元素)
真正复杂的地方在于:迭代器失效规则与分配器行为耦合紧密,而跨 DLL 边界传递 vector(尤其含自定义分配器)极易出错——这些细节往往被教程跳过,但线上崩溃常源于此。









