C++标准模板库【STL】—— vector快速上手
Vector 容器基础知识详解
一、Vector 容器概述
1. 基本定义
- 动态数组:STL中最常用的序列容器
- 内存连续:元素存储在连续内存空间
- 自动扩容:插入元素超出容量时自动扩展内存(通常2倍扩容)
2. 核心特性对比
特性 | Vector | 原生数组 |
---|---|---|
内存管理 | ✅ 自动扩容/缩容 | ❌ 固定大小 |
随机访问 | ⚡️ O(1) | ⚡️ O(1) |
尾部操作 | ⚡️ O(1) 高效 | N/A |
头部操作 | ⚠️ O(n) 低效 | N/A |
迭代器安全 | ⚠️ 插入/删除失效 | ✅ 稳定 |
线程安全 | ❌ 需外部同步 | ❌ 非线程安全 |
二、vector的构造方法
带参数构造函数
C++ 中的 vector
容器提供了多种构造方式,以下是三种主要的带参数构造方法:
-
区间构造
vector(beg, end);
将[beg, end)
区间内的元素拷贝给容器(左闭右开)。 -
填充构造
vector(n, elem);
构造包含n
个相同元素elem
的容器。 -
拷贝构造
vector(const vector &vec);
拷贝构造函数,复制另一个vector
容器的所有元素。
基本声明语法
// 基础声明格式
vector<T> vecT;
// 示例声明
vector<int> vecInt; // 存放 int 类型
vector<float> vecFloat; // 存放 float 类型
vector<string> vecString; // 存放 string 类型
// 自定义类型
class CA {};
vector<CA*> vecpCA; // 存放指针
vector<CA> vecCA; // 存放对象
示例代码
#include<iostream>
#include<vector>
using namespace std;
int main()
{
int iArray[] = { 0,1,2,3,4 };
// 1. 数组区间构造
vector<int> vecIntA(iArray, iArray + 5); // 拷贝整个数组(左闭右开)
// 2. 迭代器区间构造
vector<int> vecIntB(vecIntA.begin(), vecIntA.end()); // 拷贝整个vector
//vector<int> vecIntB(vecIntA.begin(), vecIntA.begin() + 3); // 只拷贝前3个元素
// 3. n个elem构造
vector<int> vecIntC(3, 9); // 构造包含3个9的vector
for (int i = 0;i < 3;i++) {
cout << vecIntC[i] << " " ;
}
cout << endl;
// 4. 拷贝构造
vector<int> vecIntD(vecIntA); // 拷贝整个vecIntA
for (int i = 0;i < 5;i++) {
cout << vecIntD[i] << " ";
}
cout << endl;
return 0;
}
三、vector的赋值
示例代码
#include<iostream>
#include<vector>
using namespace std;
// 辅助函数:打印 vector 内容
void printVector(const vector<int>& vec, const string& name) {
cout << name << ": [ ";
for (int num : vec) {
cout << num << " ";
}
cout << "]" << endl;
}
int main()
{
vector<int> vecIntA, vecIntB, vecIntC, vecIntD;
int iArray[] = { 0, 1, 2, 3, 4 };
// 操作1: 用数组初始化 vecIntA
vecIntA.assign(iArray, iArray + 5); // 用其它容器的迭代器作参数
printVector(vecIntA, "操作1后的vecIntA"); // 输出: [ 0 1 2 3 4 ]
// 操作2: 用 vecIntA 初始化 vecIntB
vecIntB.assign(vecIntA.begin(), vecIntA.end());
printVector(vecIntB, "操作2后的vecIntB"); // 输出: [ 0 1 2 3 4 ]
vecIntB.assign(vecIntA.begin()+2, vecIntA.end()-1);
printVector(vecIntB, "操作2后的vecIntB"); // 输出: [ 2 3 ]
// 操作3: 直接初始化 vecIntC
vecIntC.assign(3, 9);
printVector(vecIntC, "操作3后的vecIntC"); // 输出: [ 9 9 9 ]
// 操作4: 用 operator= 赋值
vecIntD = vecIntA;
printVector(vecIntD, "操作4后的vecIntD"); // 输出: [ 0 1 2 3 4 ]
// 操作5: 交换 vecIntA 和 vecIntD
vecIntA.swap(vecIntB);
printVector(vecIntA, "操作5后的vecIntA"); // 输出: [ 2 3 ]
printVector(vecIntB, "操作5后的vecIntD"); // 输出: [ 0 1 2 3 4 ]
// 注意:因交换前内容相同,结果不变
return 0;
}
四、vector的大小
1. 获取容器中元素数量
vector.size();
返回容器中元素的个数
2. 检查容器是否为空
vector.empty();
判断容器是否为空
3. 调整容器大小(默认填充)
vector.resize(num);
重新指定容器的长度为num
若容器变长,则以默认值填充新位置
若容器变短,则末尾超出容器长度的元素被删除
4. 调整容器大小(指定填充值)
vector.resize(num, elem);
重新指定容器的长度为num
若容器变长,则以elem值填充新位置
若容器变短,则末尾超出容器长度的元素被删除
示例代码
#include<iostream>
#include<vector>
using namespace std;
int main()
{
vector<int> v1;
cout << "v1.size" << v1.size() << endl;
if (v1.empty())
{
cout << "v1 is empty" << endl;
}
int iArray[] = { 0,1,2,3,4 };
v1.assign(iArray, iArray + 5);
cout << "赋值后:";
for (int i = 0; i < v1.size(); i++)
cout << v1[i] << " ";
cout << endl;
// 将容器的长度变长
v1.resize(10);
cout << "变长后(默认填充): ";
for (int i = 0; i < v1.size(); i++)
cout << v1[i] << " ";
cout << endl;
// 将容器的长度变短
v1.resize(3);
cout << "变短后: ";
for (int i = 0; i < v1.size(); i++)
cout << v1[i] << " ";
cout << endl;
// 将容器的长度变长,并且扩展出来的新元素赋值为指定的值!
v1.resize(10, 100);
cout << "变长后(指定填充值100): ";
for (int i = 0; i < v1.size(); i++)
cout << v1[i] << " ";
cout << endl;
return 0;
}
五、vector元素的访问方式
示例代码
#include <iostream>
#include <vector>
using namespace std;
int main() {
int a[] = { 1,2,3,4 };
vector<int> v1(a, a + 4);
for (int i = 0; i < v1.size(); i++)
cout << v1[i] << " ";
cout << endl;
// v1[8] = 100; // 危险的下标越界访问
// v1.at(8) = 100; // 会抛出std::out_of_range异常
return 0;
}
六、vector插入函数insert的使用
1. 在pos位置插入一个elem元素的拷贝, 返回新数据的位置
vector.insert(pos,elem);
2. 在pos位置插入n个elem数据, 无返回值
vector.insert(pos,n,elem);
3. 在pos位置插入[beg,end)区间的数据, 无返回值
vector.insert(pos,beg,end);
示例代码
#include <iostream>
#include <vector>
using namespace std;
int main() {
int a[] = { 1,2,3,4 };
vector<int> v1(a, a + 4);
for (int i = 0; i < v1.size(); i++)
cout << v1[i] << " ";
cout << endl;
// 使用已有的v1容器(不再重新声明)
v1.clear(); // 清空原有内容,准备重新添加元素
// 尾部添加元素
v1.push_back(1); // 在容器尾部加入一个元素
v1.push_back(3);
v1.push_back(5);
v1.push_back(7);
v1.push_back(9);
// 尾部移除元素
v1.pop_back(); // 删除最后一个元素 (9)
v1.pop_back(); // 删除最后一个元素 (7)
// 验证结果
cout << "当前元素:";
for (int num : v1) {
cout << num << " ";
}
cout << endl; // 输出:1 3 5
// 在指定位置插入单个元素
v1.insert(v1.begin() + 3, 100); // 注意:第一个参数为迭代器位置
cout << "插入单个元素后:";
for (int i = 0; i < v1.size(); i++)
cout << v1[i] << " ";
cout << endl;
// 此时v1内容: 1 3 5 100
// 在指定位置插入多个相同元素
v1.insert(v1.begin() + 3, 3, 1000); // 在下标3位置插入3个1000
cout << "插入多个相同元素后:";
for (int i = 0; i < v1.size(); i++)
cout << v1[i] << " ";
cout << endl;
// 此时v1内容: 1 3 5 1000 1000 1000 100
// 在指定位置插入区间元素
int b[] = { 40, 50, 60, 70, 80, 90 };
// 将b数组中索引[1,5)区间的元素插入到v1位置7
v1.insert(v1.begin() + 7, b + 1, b + 5);
cout << "插入区间元素后:";
for (int i = 0; i < v1.size(); i++)
cout << v1[i] << " ";
cout << endl;
// 此时v1内容: 1 3 5 1000 1000 1000 100 50 60 70 80
vector<int> v2(b, b + 6); // 用b数组中前6个元素初始化v2
// 将v2容器中的50、60、70插入到v1索引7的位置
v1.insert(v1.begin() + 7, v2.begin() + 1, v2.begin() + 4);
// 输出结果
cout << "插入操作后:";
for (int i = 0; i < v1.size(); i++)
cout << v1[i] << " ";
cout << endl;
return 0;
}
七、vector元素的删除
pop_back()
只能删除最后一个元素,无法指定位置。erase()
会导致后续元素前移,迭代器可能失效。clear()
只是清空元素,不改变容量(capacity)。erase-remove
是标准删除指定值元素的高效方案。
示例代码
#include <iostream>
#include <vector>
using namespace std;
int main() {
// 创建并初始化 vector
vector<int> v;
v.push_back(10);
v.push_back(20);
v.push_back(30);
v.push_back(40);
v.push_back(50);
// 方法1: pop_back() 删除最后一个元素
v.pop_back(); // 删除50
cout << "pop_back() 后: ";
for (auto num : v) cout << num << " "; // 输出: 10 20 30 40
cout << endl;
// 方法2: erase(pos) 删除指定位置的元素
v.erase(v.begin() + 1); // 删除索引1处的元素 (20)
cout << "erase(pos) 后: ";
for (auto num : v) cout << num << " "; // 输出: 10 30 40
cout << endl;
// 方法3: erase(pos1, pos2) 删除区间元素
v.erase(v.begin() + 1, v.end()); // 删除索引1到末尾的所有元素
cout << "erase(beg, end) 后: ";
for (auto num : v) cout << num << " "; // 输出: 10
cout << endl;
// 重置 vector
v = { 10, 20, 30, 40, 50, 60, 70 };
// 方法4: clear() 删除所有元素
v.clear();
cout << "clear() 后 size: " << v.size(); // 输出: 0
return 0;
}
八、vector迭代器
构造迭代器
vector<int>::iterator it;
示例代码
#include <iostream>
#include <vector>
using namespace std;
int main() {
// 定义整型数组
int iArray[] = { 100, 1, 20, 30, 40 };
// 创建vector容器并用数组初始化
vector<int> vecIntA;
vecIntA.assign(iArray, iArray + 5); // 将数组元素赋值给vector
// 构造迭代器
vector<int>::iterator it;
// 让迭代器指向vecIntA的第一个元素
it = vecIntA.begin();
// 通过迭代器遍历vector所有元素
for (it = vecIntA.begin(); it != vecIntA.end(); it++) {
cout << *it << " "; // 输出当前迭代器指向的元素值
}
cout << endl; // 输出:100 1 20 30 40
// 重置迭代器位置
it = vecIntA.begin(); // 指向第一个元素 (100)
// 迭代器前进2个位置
it = it + 2; // 指向第三个元素 (20)
cout << *it << endl; // 输出:20
// 迭代器后退2个位置
it = it - 2; // 返回第一个元素 (100)
cout << *it << endl; // 输出:100
return 0;
}
九、迭代器失效问题
1. 什么是迭代器失效?
迭代器失效指的是在对容器进行修改操作后,之前获取的迭代器可能不再有效。此时,如果继续使用这些迭代器进行访问或操作,程序可能崩溃或行为异常。
2. vector
中常见导致迭代器失效的操作
操作 | 迭代器失效情况 | 说明 |
---|---|---|
插入元素 (push_back , insert ) | 可能导致所有迭代器失效(若发生扩容) | 容器扩容时,会重新分配内存,旧迭代器失效 |
删除元素 (erase , pop_back ) | 被删除元素及其后的元素迭代器失效 | 后续元素位置前移,相关迭代器失效 |
clear() | 所有迭代器失效 | 容器清空,迭代器失效 |
不修改容器大小 | 迭代器通常保持有效 | 例如读取操作,不影响迭代器 |
3. 为什么会失效?
vector
底层是连续的内存数组。当发生扩容(容量不足时自动增长),会重新分配更大的内存块,并把原数据拷贝过去,旧内存释放,之前指向旧内存的迭代器就失效了。
删除元素时,后续元素会前移,导致它们的内存位置改变,因此指向这些元素的迭代器也失效。
4. 如何避免迭代器失效?
- 避免在使用迭代器过程中修改容器结构(如插入、删除);
- 插入或删除操作后,重新获取迭代器;
- 使用索引访问替代迭代器访问(当可行时);
- 对于需要频繁插入删除的场景,考虑使用链表(
list
)等不会因插入删除导致迭代器失效的容器。
示例代码
#include <iostream>
#include <vector>
using namespace std;
int main() {
// 创建vector容器v
vector<int> v;
// 向vector尾部插入元素
v.push_back(1); // 插入第一个元素:1
v.push_back(2); // 插入第二个元素:2
v.push_back(3); // 插入第三个元素:3
v.push_back(4); // 插入第四个元素:4
// 创建迭代器it,指向v的第四个元素位置(索引3,值为4)
vector<int>::iterator it = v.begin() + 3;
// 在迭代器位置插入元素8,并更新迭代器
// insert操作返回指向新插入元素的新迭代器
it = v.insert(it, 8); // 如果不给it重新赋值会失效会出错的
// 输出新迭代器指向的元素值
cout << *it << endl; // 输出:8
vector<int> cond = { 1, 2, 3, 3, 3, 3, 4, 5, 6 };
for (auto it = cond.begin(); it != cond.end(); ) {
if (*it == 3) {
// 关键修正:接收 erase() 返回的新迭代器
it = cond.erase(it);
// 可选:输出被删除元素的后继值
if (it != cond.end()) {
cout << "后一个元素: " << *it << endl;
}
}
else {
it++; // 仅当未删除时移动迭代器
}
}
// 验证结果
cout << "剩余元素: ";
for (int num : cond) {
cout << num << " ";
}
// 输出: 1 2 4 5 6
return 0;
}