本文对 C++标准库中的迭代器。
目录
- [1 概述](#1 概述)
- [2 示例](#2 示例)
-
- [2.1 显式使用](#2.1 显式使用)
- [2.2 隐式使用](#2.2 隐式使用)
- [3 类别](#3 类别)
-
- [3.1 分类](#3.1 分类)
- [3.2 通用迭代器规则](#3.2 通用迭代器规则)
- [3.3 迭代器类别层级关系](#3.3 迭代器类别层级关系)
- [4 其他](#4 其他)
1 概述
迭代器是一种对象,
用于遍历 C++标准库容器内的元素,并访问其中单个元素。所有 C++标准库容器都提供迭代器,让通用算法可以用统一方式访问容器元素,无需关心底层容器的具体类型。你有两种使用迭代器的方式:
显式使用:调用成员函数 / 全局函数(如begin()和end()),通过运算符(++或--)前后移动迭代器;
隐式使用:通过范围 for 循环或(对于某些迭代器类型)下标运算符 \[\];
标准库统一规则:在 C++标准库中,begin() 指向序列第一个元素;end() 永远指向最后一个元素的下一位;
全局函数 begin()、end() 可以获取任意容器的首尾迭代器;
2 示例
2.1 显式使用
典型显式迭代器循环访问容器中的所有元素,如下所示:
cpp
#include <vector>
#include <iostream>
int main() {
std::vector<int> vec{ 0,1,2,3,4 };
for (auto it = begin(vec); it != end(vec); it++)
{
// Access element using dereference operator
std::cout << *it << " ";
}
}
运行结果:
2.2 隐式使用
使用for循环更加简单的完成相同操作:
cpp
#include <vector>
#include <iostream>
int main() {
std::vector<int> vec{ 0,1,2,3,4 };
for (auto num : vec)
{
// no dereference operator
std::cout << num << " ";
}
}
运行结果:
3 类别
3.1 分类
迭代器分为五类,按功能从弱到强排序如下:
- 输出迭代器(Output)
- 输出迭代器 X 只能通过 ++ 向后遍历序列;
- 通过解引用 * 仅能对元素写入一次,不可重复读取 / 重复写入;
- 输入迭代器(Input)
- 输入迭代器 X 仅能用 ++ 向后遍历;
- 可通过 * 多次读取元素;
- 支持 ==、!= 运算符来比较输入迭代器;
- 一旦递增该迭代器的任意一份副本,其他所有副本都不能再安全地判等、解引用或自增;
- 前向迭代器(Forward)
- 前向迭代器完全具备输入迭代器能力,只能 ++ 向后遍历;
- 可无限次读取元素,对非 const 容器可无限次写入;
- 支持 -> 访问成员、== / != 比较;
- 可以拷贝多份迭代器副本,每份副本都能独立解引用、自增;
- 未绑定任何容器初始化的前向迭代器称为空前向迭代器,所有空前向迭代器互相相等;
- 双向迭代器(Bidirectional)
- 双向迭代器可完全替代前向迭代器;额外支持递减操作 --X、X--;
- 其余成员访问、比较规则和前向迭代器一致;
- 随机访问迭代器(Random access)
- 随机访问迭代器可完全替代双向迭代器;
- 下标运算符 \[\] 直接访问元素;
- +、-、+=、-= 一次性跳跃多个元素、计算迭代器间距;
- 支持完整大小比较:==、!=、<、> 、<=、>=。
| 类别 | 移动方向 | 核心限制 | 典型容器 |
|---|---|---|---|
| Output | 仅 ++ | 每个位置只能写1次,不可读 | ostream_iterator |
| Input | 仅 ++ | 自增后副本全部失效 | istream_iterator |
| Forward | 仅 ++ | 副本独立有效,可反复读写 | unordered_map / set |
| Bidirectional | ++ / -- | 可前后移动 | list / map / set |
| RandomAccess | 任意跳跃 | \[\]、± 数字、大小比较 | vector / deque / string / 数组指针 |
说明:
- Input 迭代器的致命限制
- 只要 it++,其他拷贝出来的迭代器全部报废,不能再用;而 Forward 迭代器无此限制,拷贝后互不干扰;
- 替换规则:强迭代器兼容弱迭代器
- 比如 sort 需要随机访问迭代器,list 只有双向迭代器,因此 list 不能用 std::sort,只能用自身成员 sort。
- 裸指针 = 随机访问迭代器
- 数组指针可以传给所有标准算法,因为满足随机访问全部要求;
- 空迭代器(null forward iterator)
- 仅 Forward 及以上才有该概念,默认构造、未绑定容器的迭代器互等,但不能解引用;
3.2 通用迭代器规则
- 所有迭代器都支持
拷贝、赋值;- 迭代器是轻量对象,通常以值
传递 / 返回,而非引用;- 对有效迭代器执行上文所有操作都
不会抛出异常;
3.3 迭代器类别层级关系
注:箭头含义:右方可替代左方
- 只写场景(输出)
- 输出迭代器 → 前向迭代器 → 双向迭代器 → 随机访问迭代器
- 算法要求输出迭代器时,更强类型迭代器都能兼容使用,反之不行;
- 只读场景(输入)
- 输入迭代器 → 前向迭代器 → 双向迭代器 → 随机访问迭代器
- 输入迭代器是只读体系里最弱的一类;
- 读写均可场景
- 前向迭代器 → 双向迭代器 → 随机访问迭代器
4 其他
补充规则:
原生裸指针天然等价随机访问迭代器,根据读写权限,可充当任意一类迭代器;
非指针类型的自定义迭代器,必须提供 iterator_traits<Iterator> 所需内嵌成员类型,最简单实现方式是公有继承标准基类 std::iterator;
注意:理解每类迭代器的能力与限制,是看懂标准库容器、算法如何使用迭代器的关键。范围 for 循环可省去手动迭代器操作;
MSVC 提供带检查迭代器与调试迭代器,运行时拦截越界、非法迭代器操作;

