C++ 迭代器全解析:从概念到实践,掌握 STL 的灵魂
迭代器(Iterator)是 STL 的核心灵魂,它统一了所有容器的遍历方式,让 vector、list、map、set 等不同数据结构,能用同一套语法遍历、访问、修改,彻底屏蔽底层实现差异。
这篇会从概念 → 分类 → 原理 → 实战 → 手写迭代器,彻底讲透。
一、迭代器是什么?(一句话理解)
迭代器就是指向容器元素的“智能指针” :
- 行为像指针:支持
*it、++it、--it、-> - 作用:遍历容器 + 访问元素,不关心容器底层是数组、链表还是树
- 语法统一:所有 STL 容器遍历代码几乎一模一样
没有迭代器,vector 用下标、list 用节点指针、map 用二叉树指针,代码会彻底混乱。
二、迭代器核心语法(所有容器通用)
// 1. 获取迭代器
auto it = container.begin(); // 指向第一个元素
auto end = container.end(); // 指向【最后一个元素的下一个位置】
// 2. 通用遍历(最标准写法)
for (auto it = vec.begin(); it != vec.end(); ++it) {
cout << *it << endl; // 解引用访问元素
}
// 3. 范围for(本质就是迭代器语法糖)
for (auto& x : container) { ... }
关键规则:
-
end() 不是最后一个元素,不能解引用 - 优先用
++it 而不是 it++(更高效) - 只读遍历用
const_iterator
三、迭代器的 5 种分类(必须掌握)
按功能强弱排序,越往下功能越强:
1. 输入迭代器(Input)
只能读一次,单向遍历 例:istream_iterator
2. 输出迭代器(Output)
只能写一次,单向遍历 例:ostream_iterator
3. 前向迭代器(Forward)
可多次读写,只能向前走 例:forward_list
4. 双向迭代器(Bidirectional)
支持 ++ 和 --,可前进可后退 例:list / map / set
5. 随机访问迭代器(Random Access)
最强!支持 + - [] < > 等所有运算 例:vector / deque / 原生数组
map/set 都是双向迭代器,不支持 it+5 这种跳跃操作!
四、迭代器常用配套工具(STL 标准)
#include <iterator>
advance(it, n); // 让迭代器前进 n 步(通用所有迭代器)
next(it); // 下一个元素
prev(it); // 上一个元素
distance(it1, it2); // 两个迭代器之间的元素个数
这些函数自动适配迭代器类型,随机访问 O(1),双向 O(n)。
五、实战:4 大容器迭代器遍历(代码完全统一)
你会发现写法几乎一模一样,这就是迭代器的威力!
#include <iostream>
#include <vector>
#include <list>
#include <map>
#include <set>
using namespace std;
int main() {
// 1. vector(随机访问迭代器)
vector<int> vec = {1,2,3};
for (auto it = vec.begin(); it != vec.end(); ++it) {
cout << *it << " ";
}
// 2. list(双向迭代器)
list<int> lst = {1,2,3};
for (auto it = lst.begin(); it != lst.end(); ++it) {
cout << *it << " ";
}
// 3. set(双向迭代器)
set<int> st = {1,2,3};
for (auto it = st.begin(); it != st.end(); ++it) {
cout << *it << " ";
}
// 4. map(双向迭代器,key-value)
map<int, string> mp = {{1,"a"},{2,"b"}};
for (auto it = mp.begin(); it != mp.end(); ++it) {
cout << it->first << ":" << it->second << " ";
}
return 0;
}
六、const_iterator & 反向迭代器
1. const_iterator
只读迭代器,不能修改元素
vector<int>::const_iterator it;
for (auto it = vec.cbegin(); it != vec.cend(); ++it) {
// *it = 10; 错误!只读
}
2. reverse_iterator
反向遍历,从尾到头
for (auto it = vec.rbegin(); it != vec.rend(); ++it) {
cout << *it << " ";
}
七、进阶:手写一个简易迭代器(理解底层原理)
迭代器本质就是封装指针/节点,重载运算符。 我们给一个简单数组实现迭代器:
#include <iostream>
using namespace std;
// 模拟一个简单数组容器
class MyVector {
private:
int* arr;
int size;
public:
MyVector(int* a, int s) : arr(a), size(s) {}
// 迭代器:封装原生指针
typedef int* iterator;
// begin / end
iterator begin() { return arr; }
iterator end() { return arr + size; }
};
int main() {
int arr[] = {10,20,30};
MyVector vec(arr, 3);
// 使用迭代器遍历
for (MyVector::iterator it = vec.begin(); it != vec.end(); ++it) {
cout << *it << " ";
}
return 0;
}
map/set 迭代器底层就是封装红黑树节点,++ 就是走树的中序遍历!
八、迭代器失效问题(高频坑点)
容器修改后,迭代器可能变成“野指针”!
1. vector 失效
插入/删除导致内存重新分配,所有迭代器失效
2. list / map / set 失效
插入不失效删除只有被删节点迭代器失效,其他都有效
// 错误示范:vector 插入后 it 失效
auto it = vec.begin();
vec.insert(it, 100);
// *it 未定义行为!
九、总结:迭代器核心思想
- 统一遍历接口:屏蔽 vector/list/map 底层差异
- 智能指针:行为像指针,但更安全、更通用
- STL 灵魂:算法、容器、迭代器三者协作基础
- map/set 迭代器 = 红黑树节点封装,中序遍历输出有序
速记口诀
- 迭代器 = 智能指针
- 通用遍历:
begin() 到 end(),++it - vector 随机访问,map/set 只能双向
- 修改容器小心迭代器失效
掌握迭代器,你才算真正入门 STL!
需要我给你整理 「迭代器 + 算法 + 容器」三合一实战模板 吗?直接复制就能用在项目和面试里。