迭代器是C++中连接容器与算法的关键抽象,通过统一的接口实现高效、灵活的数据操作。理解迭代器的分类、操作、失效机制及适配器,是编写健壮STL代码的基础。
一、迭代器的定义
迭代器是一种对象,它提供了一种访问容器元素的方式,而无需暴露容器的内部实现。迭代器的行为类似于指针,但它是一个更高层次的抽象,支持多种容器类型(如数组、链表、树等)。
核心作用:
-
提供统一接口遍历容器,无论容器类型如何。
-
实现算法与容器的解耦,使算法可以通过迭代器操作容器。
-
最重要的一点是迭代器是左闭右开区间,即最左边能取到,但是最右边取不到,换成数组也是一样的。
二、迭代器的分类
迭代器按功能分为五类(从弱到强):
类型 | 功能描述 | 示例容器/迭代器 |
---|---|---|
输入迭代器 | 只读,单次遍历(只能向前) | istream_iterator |
输出迭代器 | 只写,单次遍历 | ostream_iterator |
前向迭代器 | 可读写,支持多次向前遍历 | forward_list 的迭代器 |
双向迭代器 | 可向前或向后遍历(++ 和-- ) | list 、set 、map |
随机访问迭代器 | 支持任意跳跃访问(+n 、-n 、< 、[] 等),时间复杂度为O(1) | vector 、deque 、array |
三、迭代器的运算符
迭代器通过运算符重载实现其功能。不同类别的迭代器支持的运算符不同:
运算符 | 功能描述 | 支持迭代器类型 |
---|---|---|
*iter | 解引用,获取迭代器指向元素的引用 | 除输出迭代器外的所有类型 |
iter->member | 访问元素的成员(等价于(*iter).member ) | 输入/前向/双向/随机访问 |
++iter / iter++ | 移动到下一个元素(前向移动) | 所有类型(除纯输出迭代器) |
--iter / iter-- | 移动到上一个元素(反向移动) | 双向/随机访问 |
iter1 == iter2 | 判断两个迭代器是否指向同一位置 | 所有类型 |
iter1 != iter2 | 判断两个迭代器是否指向不同位置 | 所有类型 |
iter + n / iter - n | 向前或向后移动n 个位置(随机访问) | 随机访问 |
iter[n] | 访问距离当前迭代器n 个位置的元素(等价于*(iter + n) ) | 随机访问 |
< , > , <= , >= | 比较两个迭代器的位置顺序 | 随机访问 |
四、支持偏移量的迭代器
-
支持偏移量的迭代器:
-
只有随机访问迭代器支持直接加上或减去偏移量(如
it + 5
、it - 3
)。 -
典型容器:
std::vector
、std::deque
、std::array
、原生数组。
-
-
不支持偏移量的迭代器:
-
双向迭代器(如
std::list
、std::set
、std::map
)和前向迭代器(如std::forward_list
)不支持直接加上偏移量。 -
可以使用
std::advance
、std::next
或std::prev
来移动迭代器。
-
示例代码:
#include <iostream>
#include <vector>
#include <list>
#include <iterator> // 包含std::advanceint main() {// 示例1:随机访问迭代器std::vector<int> vec = {10, 20, 30, 40, 50};auto vit = vec.begin();vit = vit + 3; // 支持偏移量std::cout << *vit << "\n"; // 输出: 40// 示例2:双向迭代器std::list<int> lst = {1, 2, 3, 4, 5};auto lit = lst.begin();std::advance(lit, 2); // 使用std::advance移动迭代器std::cout << *lit << "\n"; // 输出: 3return 0;
}
五、迭代器适配器
迭代器适配器是对现有迭代器的封装,提供额外的功能:
-
反向迭代器:
-
从容器的末尾向开头遍历。
std::vector<int> vec = {1, 2, 3, 4}; for (auto rit = vec.rbegin(); rit != vec.rend(); ++rit) {std::cout << *rit << " "; // 输出: 4 3 2 1 }
-
-
插入迭代器:
-
back_inserter
:向容器尾部插入元素。 -
front_inserter
:向容器头部插入元素。 -
inserter
:向指定位置插入元素。std::vector<int> dest; std::copy(vec.begin(), vec.end(), std::back_inserter(dest));
-
六、迭代器失效问题(特别注意)
某些容器操作可能导致迭代器失效:
-
序列容器(如
vector
、deque
):-
插入/删除元素可能使所有迭代器失效(内存重新分配)。
-
-
链表容器(如
list
):-
插入不会使迭代器失效。
-
删除仅使被删除元素的迭代器失效。
-
-
关联容器(如
map
、set
):-
插入不会失效。
-
删除仅使被删除元素的迭代器失效。
-
示例:删除vector
中的偶数元素
std::vector<int> vec = {1, 2, 3, 4, 5};
for (auto it = vec.begin(); it != vec.end();) {if (*it % 2 == 0) {it = vec.erase(it); // erase返回下一个有效迭代器} else {++it;}
}
七、迭代器的使用
-
获取迭代器:
-
begin()
:指向第一个元素。 -
end()
:指向最后一个元素的下一个位置(“尾后”位置)。 -
cbegin()
、cend()
:常量迭代器。 -
rbegin()
、rend()
:反向迭代器。
-
-
遍历容器:
std::vector<int> vec = {1, 2, 3}; for (auto it = vec.begin(); it != vec.end(); ++it) {std::cout << *it << " "; }
-
基于范围的for循环(C++11):
for (const auto& val : vec) {std::cout << val << " "; }
八、迭代器的操作
-
遍历:使用
++
、--
、*
等运算符。 -
比较:使用
==
、!=
、<
、>
等运算符。 -
移动:使用
std::advance
、std::next
、std::prev
。 -
插入/删除:使用
insert
、erase
等容器方法。