vector 是 C++ 标准模板库里面的动态顺序容器,本质就是可以自动扩容的数组,和普通固定长度数组最大区别就是长度不用提前写死,能够在运行阶段新增删除元素,内存连续存放,支持随机访问,日常写代码做动态数组 存储批量数据 传参返回数组类数据的时候非常常用,它属于 STL 核心组件,使用的时候需要引入头文件 vector,模板尖括号里面填写你要存储的数据类型,很多新手容易混淆 vector 扩容原理 迭代器失效 内存释放这几个关键点,这份内容从定义初始化 增删改查 迭代器 常用算法 性能特点 常见坑全部展开讲解,适合从入门到实际项目编码使用。
一 头文件与基础定义
使用 vector 首先要引入头文件
include vector
using namespace std 或者写 stdvector
定义语法
stdvector 元素类型 变量名
基础定义示例
vector int v1 空的 int 类型 vector
vector int v2 10 定义长度为 10,全部初始化为 0
vector int v3 10 5 定义长度 10,每一个元素都是 5
vector int v4 1 2 3 列表初始化 C++11 支持
vector int v5 v2 拷贝构造,复制 v2 全部内容
二 核心常用操作清单
| 分类 | 函数 | 功能说明 |
|---|---|---|
| 访问 | at | 安全访问,越界抛出异常 |
| 访问 | operator | 下标访问,越界不检查速度更快 |
| 访问 | front | 获取第一个元素 |
| 访问 | back | 获取最后一个元素 |
| 访问 | data | 返回底层原生数组指针 |
| 增加 | push_back | 尾部追加元素 |
| 增加 | emplace_back | 尾部就地构造元素,比 push_back 效率更高 |
| 增加 | insert | 在指定迭代器位置插入元素 |
| 删除 | pop_back | 删除尾部元素 |
| 删除 | erase | 删除迭代器指向元素或者一段区间 |
| 删除 | clear | 清空全部元素,但是内存不一定释放 |
| 容量 | size | 当前元素个数 |
| 容量 | capacity | 当前已经分配的内存可容纳元素总数 |
| 容量 | reserve | 提前预留容量,避免多次扩容 |
| 容量 | resize | 修改元素个数,多出来的元素初始化,多余元素删掉 |
| 其他 | swap | 和另一个 vector 交换内容 |
| 其他 | empty | 判断 vector 是否为空,返回布尔值 |
三 遍历 vector 的几种方式
1 下标 for 循环
for int i=0 i v.size i++
cout v i
2 迭代器遍历
vector int iterator it
for it = v.begin it != v.end it++
cout it
3 范围 for 循环 C++11
for auto num v
cout num
四 扩容原理重点讲解
vector 底层是连续内存,当 push_back 之后元素数量超过当前 capacity,就会触发扩容,一般是申请一块更大的连续内存,把旧内存里面所有元素拷贝或者移动到新内存,然后释放旧内存,这个过程开销比较大,频繁扩容会降低程序运行速度。
优化方案 提前调用 reserve 预估总元素数量,一次性分配足够 capacity,避免反复拷贝移动。
重点区分 size 和 capacity
size 是现在实际存了多少个元素
capacity 是已经申请好内存,最多还能放多少元素,capacity 永远大于等于 size
clear 之后 size 变成 0,但是 capacity 不会自动缩小,如果想要释放多余内存,可以用 shrink_to_fit 或者 swap 空 vector 技巧。
五 迭代器失效 高频坑点
这个是 vector 最容易出错的地方
1 erase 删除元素之后,当前位置迭代器失效,erase 会返回下一个有效迭代器,写代码必须接收返回值
错误写法
for auto it = v.begin it != v.end it++
if 条件 v.erase it
正确写法
it = v.erase it
2 insert 插入元素之后,如果发生扩容,全部旧迭代器都会失效,没有扩容的时候,插入点之后迭代器失效
3 push_back 触发扩容之后,所有迭代器 指针 引用全部失效
六 传参和返回值
vector 传参如果直接传值,会完整拷贝一份,性能差,推荐使用 const 引用只读传参
void func const vector int v
如果函数内部要修改 vector,使用普通引用
void func vector int v
函数返回 vector,C++11 之后有移动语义,大部分场景不需要手动写指针返回,直接 return vector 就可以。
七 优缺点总结
优点
内存连续,随机访问速度快,缓存友好,接口统一,STL 算法可以直接配合使用,自动管理内存不用手动 malloc free
缺点
中间插入删除效率低,因为插入位置后面所有元素都要移动,扩容会产生拷贝开销,不适合频繁在头部插入删除,头部插入推荐 deque
【常见问题】
问题 1 vector c++ 为什么 push_back 之后迭代器会失效,vector c++ 怎么避免频繁扩容
回答 1 vector c++ 在 push_back 触发扩容的时候,底层会重新申请新的连续内存,旧内存释放,原来的迭代器绑定旧内存地址,所以全部失效,vector c++ 想要避免频繁扩容,可以提前调用 reserve 预估元素总数,提前分配好 capacity,减少多次拷贝移动元素的开销。
问题 2 vector c++ 的 clear 和 resize 有什么区别,vector c++ clear 之后内存会释放吗
回答 2 vector c++ 的 clear 是删除全部元素,size 变成 0,vector c++ 的 resize 是直接修改元素总数,可以增加或者减少元素,新增元素还会自动初始化,vector c++ 执行 clear 之后 capacity 一般不会改变,底层内存不会自动释放,想要释放多余内存可以使用 shrink_to_fit。
问题 3 vector c++ erase 删除元素的时候为什么报错,vector c++ erase 正确写法是什么
回答 3 vector c++ erase 删除元素报错大多是迭代器失效,erase 之后原来迭代器已经无效,继续自增就会越界崩溃,vector c++ 正确写法是接收 erase 返回的下一个有效迭代器,写成 it = v.erase it,不要继续使用原来旧迭代器。
问题 4 vector c++ 和普通数组对比优势是什么,vector c++ 可以存放自定义类对象吗
回答 4 vector c++ 对比普通固定数组,优势是长度动态变化,自动扩容,自带 size 等成员函数,自动管理内存,vector c++ 可以存放自定义类对象,只要这个类满足可拷贝或者可移动要求,emplace_back 可以直接就地构造自定义类对象,减少拷贝开销。
【免责申明】
本内容基于标准 C++ STL 规范进行讲解,不同编译器比如 MSVC GCC Clang 对部分扩展特性实现细节会有差异,代码示例仅作为学习参考,实际项目编译运行需要结合编译器标准版本,本内容不能替代 C++ 标准文档,编码产生的程序异常 内存泄漏 崩溃等风险由使用者自行承担。


