C++中vector的用法详解_C++标准库vector容器完全指南

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

直接说结论:std::vector 是 C++ 标准库中最常用、最值得优先掌握的序列容器,但它不是“万能数组替代品”——它的性能特征、迭代器失效规则和内存行为必须明确理解,否则容易在扩容、erase、多线程等场景踩坑。

vector 的构造和初始化有哪些安全写法?

常见错误是用 vector v(10) 误以为创建了空容器,其实它构造了含 10 个默认值(0)的 vector;更隐蔽的是 vector v{10},这创建的是含单个元素 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 和 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 更优。但对 intstring 等简单类型,差异可忽略。

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_ifv.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(尤其含自定义分配器)极易出错——这些细节往往被教程跳过,但线上崩溃常源于此。