std::vector 构造需区分括号与花括号:vector v; 为空,v(5) 创建5个0,v{1,2,3} 初始化3个元素;erase后必须用返回迭代器继续遍历,或用erase-remove惯用法。
直接说结论:std::vector 是 C++ 标准库中最常用、最值得优先掌握的序列容器,但它不是“万能数组替代品”——它的性能特征、迭代器失效规则和内存行为必须明确理解,否则容易在扩容、erase、多线程等场景踩坑。
常见错误是用 vector 误以为创建了空容器,其实它构造了含 10 个默认值(0)的 vector;更隐蔽的是 vector,这创建的是含单个元素 10 的 vector。
vector v; —— 空容器,v.size() == 0
vector v(5); —— 含 5 个 int{}(即 5 个 0)vector v{1,2,3}; —— 初始化列表,含 3 个元素vector v(other.begin(), other.end()); —— 迭代器区间构造,注意传入有效范围vector v = {1,2,3}; 这种拷贝初始化(C++17 后通常无差别,但语义不如直接列表初始化清晰)两者都尾插,但语义和开销不同: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 等简单类型,差异可忽略。
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;
v.erase(remove(v.begin(), v.end(), x), v.end());
remove_if:v.erase(remove_if(v.begin(), v.end(), [](int a){ return a
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(尤其含自定义分配器)极易出错——这些细节往往被教程跳过,但线上崩溃常源于此。