迭代器(Iterator)是 C++ STL 的核心组件之一,本质是封装了指针行为的对象,为不同容器提供统一的遍历接口—— 无论底层是数组(vector)、链表(list)、红黑树(map)还是哈希表(unordered_map),都能通过迭代器以相同的方式访问元素,实现了 “算法与容器解耦”。
一、迭代器的核心定位
迭代器的作用是连接容器和算法:
- 容器提供数据存储,算法提供通用操作(排序、查找等);
- 迭代器作为 “桥梁”,让算法无需关心容器的底层实现,只需通过迭代器访问元素。
可以把迭代器理解为 “通用版的指针”:支持 *(解引用)、++(移动)、==/!=(比较)等指针操作,但适配了不同容器的内存结构。
二、迭代器的基本特性
| 特性 | 说明 |
|---|---|
| 遍历方向 | 单向(如forward_iterator)、双向(如list的迭代器)、随机访问(如vector的迭代器) |
| 读写权限 | 普通迭代器(可读可写)、常量迭代器(const_iterator,只读) |
| 遍历范围 | 遵循 “左闭右开” 原则:begin() 指向第一个元素,就指向最后一个元素的下一个位置(不指向有效元素) |
三、迭代器的分类(按功能强弱)
STL 迭代器按功能从弱到强分为 5 类,不同容器支持的迭代器类型不同:
| 迭代器类型 | 核心能力 | 支持的操作 | 适用容器 |
|---|---|---|---|
| 输入迭代器(Input) | 只读,单向向前移动 | *it、it++、==/!= | istream_iterator |
| 输出迭代器(Output) | 只写,单向向前移动 | *it = val、it++ | ostream_iterator |
| 前向迭代器(Forward) | 可读可写,单向向前移动 | 输入 + 输出迭代器的所有操作 | forward_list、unordered_set |
| 双向迭代器(Bidirectional) | 可读可写,双向移动(++/--) | 前向迭代器 + it-- | list、map、set |
| 随机访问迭代器(Random Access) | 可读可写,随机访问(+/-/[]) | 双向迭代器 + it+n/it-n/it[] | vector、deque、array |
四、迭代器的基本用法(以 vector 为例)
1. 定义与初始化
cpp
运行
#include <iostream>
#include <vector>
using namespace std;
int main() {
vector<int> v = {10, 20, 30, 40, 50};
// 1. 普通迭代器(可读可写)
vector<int>::iterator it;
it = v.begin(); // 指向第一个元素(10)
// 2. 常量迭代器(只读,不可修改元素)
vector<int>::const_iterator cit = v.cbegin(); // cbegin() 返回const_iterator
// 3. 反向迭代器(从尾到头遍历)
vector<int>::reverse_iterator rit = v.rbegin(); // 指向最后一个元素(50)
return 0;
}
2. 遍历容器(核心场景)
cpp
运行
int main() {
vector<int> v = {10, 20, 30, 40, 50};
// 方式1:普通迭代器遍历(左闭右开)
cout << "普通迭代器遍历:";
for (vector<int>::iterator it = v.begin(); it != v.end(); it++) {
cout << *it << " "; // 解引用获取元素值
}
cout << endl; // 输出:10 20 30 40 50
// 方式2:常量迭代器遍历(只读)
cout << "常量迭代器遍历:";
for (vector<int>::const_iterator cit = v.cbegin(); cit != v.cend(); cit++) {
cout << *cit << " ";
// *cit = 100; // 错误:常量迭代器不可修改元素
}
cout << endl;
// 方式3:反向迭代器遍历(从尾到头)
cout << "反向迭代器遍历:";
for (vector<int>::reverse_iterator rit = v.rbegin(); rit != v.rend(); rit++) {
cout << *rit << " ";
}
cout << endl; // 输出:50 40 30 20 10
return 0;
}
3. 修改元素(普通迭代器)
cpp
运行
int main() {
vector<int> v = {10, 20, 30};
vector<int>::iterator it = v.begin();
*it = 100; // 修改第一个元素为100
it++; // 迭代器后移,指向第二个元素
*it += 50; // 第二个元素变为20+50=70
// 遍历验证:100 70 30
for (auto x : v) cout << x << " ";
return 0;
}
四、不同容器的迭代器差异(重点)
不同容器的底层结构不同,导致迭代器的功能和性能差异显著:
| 容器 | 迭代器类型 | 核心限制 |
|---|---|---|
vector | 随机访问迭代器 | 支持 it+n、it[],遍历 / 随机访问快 |
list | 双向迭代器 | 不支持 it+n/it[],只能 ++/-- |
map/set | 双向迭代器 | 元素只读(修改需先删除再插入) |
unordered_map | 前向迭代器 | 不支持 --,遍历顺序无序 |
array | 随机访问迭代器 | 固定大小,迭代器不可越界 |
示例(list 的迭代器限制):
cpp
运行
#include <list>
int main() {
list<int> lst = {1,2,3};
list<int>::iterator it = lst.begin();
it++; // 合法:双向迭代器支持++
it--; // 合法:支持--
// it += 2; // 错误:list迭代器不支持随机访问
// cout << it[0]; // 错误:无[]操作
return 0;
}
五、迭代器的常用技巧
1. 自动类型推导(auto 简化代码)
C++11 后可通过 auto 自动推导迭代器类型,避免冗长的类型声明:
cpp
运行
vector<string> months = {"Jan", "Feb", "Mar"};
// auto 推导为 vector<string>::iterator
for (auto it = months.begin(); it != months.end(); it++) {
cout << *it << " ";
}
2. 迭代器与算法结合(STL 核心用法)
算法通过迭代器操作容器,无需关心容器类型:
cpp
运行
#include <algorithm> // sort/find 头文件
int main() {
vector<int> v = {3,1,4,1,5};
// 排序:通过迭代器指定范围
sort(v.begin(), v.end()); // v变为{1,1,3,4,5}
// 查找:返回指向目标元素的迭代器
auto it = find(v.begin(), v.end(), 3);
if (it != v.end()) {
cout << "找到元素:" << *it << endl; // 输出:找到元素:3
}
return 0;
}
3. 迭代器失效问题(避坑重点)
修改容器(插入 / 删除元素)可能导致迭代器失效(指向非法内存),需注意:
vector:插入 / 删除元素可能导致内存重分配,迭代器失效;list:插入元素不失效,删除元素仅失效指向被删元素的迭代器;map:插入 / 删除元素仅失效指向被删元素的迭代器。
示例(vector 迭代器失效修复):
cpp
运行
vector<int> v = {1,2,3,4};
// 错误:删除元素后,it 失效,++it 会崩溃
// for (auto it = v.begin(); it != v.end(); it++) {
// if (*it == 2) v.erase(it);
// }
// 正确:用 erase 返回的新迭代器更新
for (auto it = v.begin(); it != v.end();) {
if (*it == 2) {
it = v.erase(it); // erase 返回下一个有效迭代器
} else {
it++;
}
}
六、迭代器的核心优势
- 接口统一:不同容器的遍历方式一致,算法可复用(如
sort可排序vector,也可排序array); - 类型安全:编译期检查迭代器类型,避免原生指针的越界风险;
- 解耦设计:算法与容器分离,新增容器只需实现迭代器,无需修改算法;
- 功能扩展:支持反向迭代器、常量迭代器等,适配不同场景需求。
总结
迭代器是 STL 的 “灵魂”,核心是为不同容器提供统一的访问接口。掌握迭代器的关键:
- 理解 “左闭右开” 的遍历范围;
- 区分不同容器的迭代器类型(尤其是随机访问 vs 双向 / 前向);
- 规避迭代器失效问题;
- 结合
auto和算法简化代码。
625

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



