第四节 · 游走于每一处 · 迭代器

在学习 stringvector 时,我们已经多次见到了迭代器(Iterator)。迭代器是 C++ 标准库的核心概念之一,它提供了一种统一的方式来访问容器中的元素。

如果把容器比作一条街道,元素比作街道上的房子,那么迭代器就像是一个邮递员——它知道如何从一家走到另一家,而不需要知道街道的具体布局。


什么是迭代器

迭代器是一种类似指针的对象,它可以:

  • 指向容器中的某个元素

  • 通过递增/递减移动到相邻的元素

  • 通过解引用访问它指向的元素

最简单的理解方式:迭代器就是"泛化的指针"

vector<int> v = {10, 20, 30, 40, 50};

// 获取指向第一个元素的迭代器
vector<int>::iterator it = v.begin();

// 解引用,获取元素的值
cout << *it << endl;  // 10

// 移动到下一个元素
++it;
cout << *it << endl;  // 20

// 移动到上一个元素
--it;
cout << *it << endl;  // 10

begin() 和 end()

每个标准库容器都提供 begin()end() 成员函数:

  • begin():返回指向第一个元素的迭代器

  • end():返回指向最后一个元素之后的位置的迭代器(不是最后一个元素!)

end() 指向的是一个"虚拟"的位置,不能解引用。它的作用是标记遍历的终点。


迭代器的运算

不同类型的迭代器支持不同的运算。对于 vectorstring,它们的迭代器是随机访问迭代器,支持所有运算:


const 迭代器

如果你不想(或不能)通过迭代器修改元素,可以使用 const 迭代器:

当容器本身是 const 的时候,begin()end() 也会返回 const_iterator。


反向迭代器

如果想从后往前遍历,可以使用反向迭代器:

注意:反向迭代器的 ++ 操作是向前移动(即向数组开头方向)。


迭代器失效

使用迭代器时需要特别注意:某些操作可能会导致迭代器失效

会导致迭代器失效的操作包括:

  • push_back():可能导致 vector 重新分配内存

  • insert():插入点之后的所有迭代器失效

  • erase():删除点及之后的所有迭代器失效

  • clear():所有迭代器失效

安全的做法是在这些操作后重新获取迭代器:


在遍历时删除元素

一个常见的错误是在遍历时删除元素:

正确的做法:


迭代器与算法

标准库的算法几乎都是通过迭代器来操作容器的:

这就是迭代器的强大之处:算法只需要知道如何使用迭代器,而不需要知道具体是什么容器。同一个 sort 算法可以用于 vectordeque、普通数组等任何支持随机访问的容器。


迭代器的类型

C++ 定义了几种迭代器类型,按功能从弱到强排列:

  1. 输入迭代器:只能单向读取

  2. 输出迭代器:只能单向写入

  3. 前向迭代器:可以单向多次读写

  4. 双向迭代器:可以双向移动(如 list

  5. 随机访问迭代器:支持所有运算(如 vectordeque、普通数组)

不同的算法对迭代器有不同的要求。比如 sort 需要随机访问迭代器,而 find 只需要输入迭代器。


迭代器是连接容器和算法的桥梁,是 C++ 泛型编程的基石。理解迭代器,你就能更好地使用标准库的强大功能。

习题

  • 使用迭代器遍历一个 vector,将其中所有偶数翻倍。

  • 使用反向迭代器,将一个字符串倒序输出。

  • 编写一个函数,使用迭代器在 vector 中查找第一个大于给定值的元素。

Last updated