
在C++编程学习路上,数组是我们最早接触的线性容器,但原生数组有着致命短板:固定长度、无法动态扩容、容易越界、内存管理繁琐。
而 STL 中的 vector 完美解决了这些痛点,它是动态可变长数组,也是 C++ STL 最常用、最重要的容器之一。不管是算法刷题、项目开发、数据存储, vector 都是刚需工具。
本文从零带你系统吃透 vector :底层原理、构造初始化、常用接口、遍历方式、扩容机制、避坑要点、实战场景,一篇搞定入门到实战。
一、Vector 是什么?
- 核心定义
vector 是 C++ STL 提供的序列式容器,底层采用连续线性内存空间实现,本质就是可以自动扩容的动态数组。
- Vector 与原生数组区别
特性 原生数组 vector
长度 固定不可变 动态自动扩容缩容
内存 栈/静态内存 堆上动态分配
越界检查 无,崩溃风险高 提供 at() 安全访问
赋值拷贝 不支持直接整体赋值 支持直接拷贝、赋值
接口 无封装接口 丰富增删查改接口
- 底层特点
-
内存连续分布,支持随机访问,下标访问效率极高;
-
插入删除中间元素效率低,需要挪动数据;
-
尾部增删效率极高,O(1) 级别;
-
自动管理内存,无需手动 new/delete 。
二、Vector 头文件与基础语法
使用 vector 必须包含头文件:
cpp
#include <vector>
using namespace std; // 初学可直接使用,项目建议不用
基础定义格式:
cpp
vector<存储类型> 容器名;
示例:
cpp
vector<int> v1; // 存储int
vector<double> v2; // 存储浮点
vector<string> v3; // 存储字符串
vector<vector<int>> v4; // 二维vector,等价二维数组
三、Vector 常见构造与初始化
- 空构造
cpp
vector<int> v;
- 指定个数初始化
cpp
// 5个元素,初始值都是0
vector<int> v(5);
- 指定个数+初始值
cpp
// 5个元素,全部初始化为10
vector<int> v(5, 10);
- 拷贝构造
cpp
vector<int> v1 = {1,2,3};
vector<int> v2(v1);
- 列表初始化(C++11 推荐)
cpp
vector<int> v = {1, 2, 3, 4, 5};
- 迭代器区间构造
cpp
vector<int> v1 = {1,2,3,4};
vector<int> v2(v1.begin(), v1.end());
四、Vector 常用核心接口
- 容量与大小相关
cpp
v.size(); // 当前元素个数
v.capacity(); // 容量,已分配内存能存多少
v.empty(); // 判断是否为空
v.resize(n); // 改变有效元素个数
v.reserve(n); // 预留容量,只开空间不初始化元素
重点区分:
-
size() :实际元素数量
-
capacity() :底层内存总容量
-
reserve 只扩容不填值, resize 会改变元素个数并初始化
- 增删操作
cpp
v.push_back(x); // 尾部插入元素
v.pop_back(); // 删除尾部元素
v.insert(pos, x); // 指定位置插入
v.erase(pos); // 删除指定位置元素
v.clear(); // 清空所有元素,不释放容量
- 元素访问
cpp
v[i]; // 下标访问,不做越界检查
v.at(i); // 安全访问,越界抛异常
v.front(); // 获取首元素
v.back(); // 获取尾元素
五、Vector 四种遍历方式
- 下标遍历(最常用)
cpp
vector<int> v = {1,2,3,4};
for(int i = 0; i < v.size(); i++)
{
cout << v[i] << " ";
}
- 迭代器遍历
cpp
for(vector<int>::iterator it = v.begin(); it != v.end(); ++it)
{
cout << *it << " ";
}
- 范围 for 循环(C++11 极简推荐)
cpp
for(auto val : v)
{
cout << val << " ";
}
- 反向迭代器遍历
cpp
for(vector<int>::reverse_iterator it = v.rbegin(); it != v.rend(); ++it)
{
cout << *it << " ";
}
六、Vector 扩容机制(核心重点)
- 扩容规则
不同编译器略有差异:
-
VS:每次扩容 1.5 倍
-
GCC:每次扩容 2 倍
-
扩容过程
-
开辟一块更大的新内存空间;
-
将旧空间所有元素拷贝到新空间;
-
释放旧内存;
-
迭代器失效。
-
开发建议
如果提前知道大概数据量,先用 reserve() 预留容量,避免多次频繁扩容,提升程序效率。
示例:
cpp
vector<int> v;
v.reserve(1000); // 提前预留1000容量,减少扩容次数
七、二维 Vector 用法(实战高频)
等价于二维数组,常用于矩阵、图邻接表:
cpp
// 3行4列,初始化为0
vector<vector<int>> arr(3, vector<int>(4, 0));
// 遍历二维vector
for(int i = 0; i < arr.size(); i++)
{
for(int j = 0; j < arr[i].size(); j++)
{
cout << arr[i][j] << " ";
}
cout << endl;
}
八、使用 Vector 常见避坑点
-
不要越界访问: [] 不检查越界,程序直接崩溃,安全场景用 at() ;
-
迭代器失效问题:扩容、插入、删除后,原有迭代器会失效,需重新获取;
-
区分 resize 和 reserve:需要元素就用 resize,只预分配空间用 reserve;
-
clear 只清空元素,不释放容量,如需释放可配合 swap 技巧;
-
频繁在中间插入删除不要用 vector,改用 list 。
九、实战小案例:用 Vector 实现数据录入与筛选
需求:输入若干整数,筛选出偶数并打印
cpp
#include <iostream>
#include <vector>
using namespace std;
int main()
{
vector<int> v;
int num;
// 录入数据,输入-1结束
while(cin >> num && num != -1)
{
v.push_back(num);
}
// 筛选偶数
cout << "所有偶数:" << endl;
for(auto val : v)
{
if(val % 2 == 0)
{
cout << val << " ";
}
}
return 0;
}
十、总结
-
vector 是动态数组,替代原生固定数组,开发必备;
-
底层连续内存,随机访问快、中间增删慢;
-
掌握构造、容量接口、增删、四种遍历是入门核心;
-
理解扩容机制、迭代器失效、resize/reserve 区别是进阶关键;
-
二维 vector 可轻松替代二维数组,算法和项目都高频使用。