文章目录
C++11 中 std::vector 超详细用法
std::vector 是 C++ 标准库中最常用、最核心的动态数组容器,底层是连续内存存储,支持动态扩容,C++11 为其新增了移动语义、列表初始化、emplace 系列函数等关键特性,大幅提升了性能和易用性。
本文会覆盖 C++11 完整特性,从基础用法到高级操作、性能优化、常见坑点全讲解。
一、vector 核心特性
- 连续内存:和普通数组一样支持随机访问,
[]访问速度 O(1) - 动态扩容:容量不足时自动分配更大内存,拷贝/移动原有元素
- C++11 新增:移动构造/赋值、列表初始化、emplace 操作、
cbegin()/cend()等 - 尾插/尾删:效率极高 O(1),中间插入/删除效率低 O(n)
- 线程不安全:多线程读写需要加锁
头文件:
#include <vector>
using namespace std; // 日常开发常用,也可写 std::vector
二、C++11 vector 初始化方式(重点)
C++11 新增列表初始化,写法更简洁。
1. 空 vector
vector<int> v1;
vector<int> v2{}; // C++11 列表初始化空容器
2. 指定大小
vector<int> v(5); // 5 个 int,默认值 0
vector<int> v{5}; // 注意!列表初始化:1 个元素,值为 5
3. 指定大小 + 初始值
vector<int> v(5, 10); // 5 个 10
4. 列表初始化(C++11 最常用)
vector<int> v = {1,2,3,4,5};
vector<int> v{1,2,3,4,5}; // 等价,省略 =
5. 拷贝/移动初始化
vector<int> v1 = {1,2,3};
vector<int> v2(v1); // 拷贝
vector<int> v3 = move(v1); // C++11 移动初始化(v1 变为空)
6. 迭代器区间初始化
int arr[] = {1,2,3};
vector<int> v(arr, arr+3);
三、元素访问
vector 提供多种安全/高效的访问方式:
| 方法 | 说明 | 越界行为 |
|---|---|---|
v[i] | 随机访问,最快 | 不检查越界,未定义行为 |
v.at(i) | 带边界检查 | 抛 out_of_range 异常 |
v.front() | 首元素 | 空容器未定义行为 |
v.back() | 尾元素 | 空容器未定义行为 |
v.data() | C++11 返回底层数组指针 |
示例:
vector<int> v = {10,20,30};
v[0] = 100; // 直接修改
v.at(1) = 200; // 安全访问
int* p = v.data(); // C++11 获取连续内存指针,兼容 C 语言接口
四、C++11 新增:emplace 系列(性能王者)
这是 C++11 对 vector 最重要的优化!
push_back:创建对象 → 拷贝/移动到容器emplace_back:直接在容器内存里构造对象,无拷贝/移动,性能更高
用法对比
// 普通对象
vector<string> v;
// push_back:先创建临时对象,再移动
v.push_back("hello");
// emplace_back:直接在 vector 内部构造,效率更高
v.emplace_back("hello");
自定义结构体更明显:
struct Person {
string name;
int age;
Person(string n, int a) : name(n), age(a) {}
};
vector<Person> v;
// push_back 需要先构造临时对象,再移动
v.push_back(Person("Alice", 20));
// emplace_back 直接传构造参数,原地构造!推荐
v.emplace_back("Bob", 25);
同理还有:
emplace:指定位置原地构造emplace_front:头部原地构造(vector 不推荐用,效率低)
五、增加元素
1. 尾部添加
vector<int> v;
v.push_back(1); // 传统
v.emplace_back(2); // C++11 推荐
v = {3,4,5}; // C++11 列表赋值
2. 指定位置插入
auto it = v.begin();
v.insert(it, 100); // 开头插入
v.insert(v.end(), 200); // 尾插
v.insert(v.begin(), 3, 5);// 插入 3 个 5
// C++11 插入初始化列表
v.insert(v.end(), {6,7,8});
六、删除元素
1. 删除尾部元素
v.pop_back();
2. 删除指定位置/区间
v.erase(v.begin()); // 删除第一个元素
// 删除区间 [first, last)
v.erase(v.begin()+1, v.end());
3. 清空所有元素
v.clear(); // 清空元素,容量不变
4. C++11 常用:按条件删除(erase-remove 习惯用法)
// 删除所有等于 3 的元素
vector<int> v = {1,2,3,3,4};
v.erase(remove(v.begin(), v.end(), 3), v.end());
v.erase(remove(v.begin(), v.end(), 3), v.end()); 简要解析(erase-remove 惯用法)
需要头文件:
#include <algorithm>
分步拆解
remove(v.begin(), v.end(), 3)
std::remove不会删除容器元素!
它把容器里不等于3的元素向前移动覆盖,返回一个新的尾迭代器 new_end;
new_end往后到v.end()的区域都是无效、待清除的残余数据。
示例:{1,2,3,3,4} → remove后变为 {1,2,4,?,?},返回指向第3个元素(4之后)的迭代器。
v.erase(new_end, v.end())
vector 的erase接收迭代器区间[first, last),真正删除区间内所有元素,释放空间。
整体作用
删除 vector 中所有值等于3的元素。
关键重点
- 不能单独只用
remove,它只是移动元素,不改变容器size(); - 顺序不能颠倒:先 remove 整理元素,再 erase 批量删除尾部垃圾;
- 时间复杂度 O(n),是 vector 删除指定值元素标准写法;
- 仅适合连续容器(vector/deque),无序容器不适用。
补充对比误区
// ❌ 错误写法(只能删除单个迭代器元素,无法批量删全部3)
for(auto it = v.begin(); it != v.end(); ){
if(*it == 3) it = v.erase(it);
else ++it;
}
erase-remove 相比循环逐个erase减少多次元素搬迁,性能更优。
七、容量与大小(非常重要)
vector 有两个核心概念:
- size:实际元素个数
- capacity:已分配内存能容纳的最大元素数(扩容前不会变)
常用函数
v.size(); // 元素个数
v.empty(); // 是否为空
v.capacity(); // 容量
v.reserve(n); // C++11 预分配 n 个元素内存,**减少扩容开销**
v.shrink_to_fit();// C++11 释放多余内存,capacity = size
重点:reserve 性能优化
如果知道数据量,提前 reserve 可以避免多次自动扩容:
vector<int> v;
v.reserve(1000); // 一次性分配 1000 个空间,后面插入不会频繁扩容
八、C++11 迭代器用法
C++11 新增const 迭代器、反向迭代器,支持范围 for 循环。
1. 普通迭代器
for(auto it = v.begin(); it != v.end(); ++it) {
*it *= 2;
}
2. const 迭代器(C++11)
不能修改元素,只读更安全:
for(auto it = v.cbegin(); it != v.cend(); ++it) {
cout << *it << endl;
}
3. 反向迭代器
for(auto it = v.rbegin(); it != v.rend(); ++it) {
// 倒序遍历
}
4. 范围 for 循环(C++11 最简洁)
// 只读
for(int x : v) cout << x << endl;
// 可修改(引用)
for(int& x : v) x *= 2;
// 高效只读(const 引用)
for(const int& x : v) cout << x << endl;
九、C++11 移动语义(vector 高性能关键)
C++11 之前 vector 赋值/传参只能拷贝,数据大时很慢。
C++11 支持移动:直接偷取原对象内存,O(1) 复杂度。
vector<int> v1 = {1,2,3};
vector<int> v2 = move(v1); // 移动,v1 变为空
作为函数返回值时,编译器自动优化移动:
vector<int> create() {
vector<int> v = {1,2,3};
return v; // C++11 自动移动,无需拷贝
}
十、vector 嵌套(二维数组)
C++11 初始化二维 vector 非常简洁:
// 3 行 4 列,初始值 0
vector<vector<int>> v(3, vector<int>(4, 0));
// C++11 列表初始化二维数组
vector<vector<int>> v = {
{1,2},
{3,4},
{5,6}
};
遍历:
for(auto& row : v) {
for(int x : row) {
cout << x << " ";
}
cout << endl;
}
十一、常见坑点(必看)
-
迭代器失效
- 插入/删除元素可能导致迭代器失效
- 扩容会导致所有迭代器、指针、引用全部失效
解决:操作后重新获取迭代器。
-
()和{}初始化区别vector<int> v(5)→ 5 个元素vector<int> v{5}→ 1 个元素,值为 5
-
中间插入/删除效率极低
vector 是连续内存,中间操作会移动大量元素,频繁操作请用std::list。 -
不要使用
v[i]越界访问
调试用at(i),会抛异常方便排查。
十二、完整 C++11 示例代码
#include <iostream>
#include <vector>
using namespace std;
struct Person {
string name;
int age;
Person(string n, int a) : name(std::move(n)), age(a) {}
};
int main() {
// 1. 列表初始化
vector<int> v = {1,2,3,4,5};
// 2. 范围 for
for(int x : v) cout << x << " ";
cout << endl;
// 3. emplace_back 原地构造
vector<Person> pv;
pv.emplace_back("Tom", 20);
pv.emplace_back("Jerry", 18);
// 4. 容量操作
v.reserve(100);
v.shrink_to_fit();
// 5. 插入初始化列表
v.insert(v.end(), {6,7,8});
// 6. const 迭代器
for(auto it = v.cbegin(); it != v.cend(); ++it) {
cout << *it << " ";
}
return 0;
}
总结
- C++11 核心升级:列表初始化、移动语义、
emplace原地构造、范围 for、cbegin/cend - 优先使用:
emplace_back>push_back,范围 for,reserve预分配 - 最佳实践:尾插尾删、提前分配内存、避免中间操作、注意迭代器失效
- vector 适用场景:需要随机访问、元素个数变化、尾部频繁增删
4569

被折叠的 条评论
为什么被折叠?



