迭代器

迭代器是一个对象,可以循环访问 C++ 标准库容器中的元素,并提供对各个元素的访问。 C++ 标准库容器全都提供迭代器,以便算法可以采用标准方式访问其元素,而不必考虑用于存储元素的容器类型。

可通过使用成员和全局函数(如 begin()end())以及运算符(如 ++--)向前或向后移动,来显式使用迭代器。 还可通过范围 for 循环或(对于某些迭代器类型)下标运算符 [],来隐式使用迭代器。

在 C++ 标准库中,序列或范围的开头是第一个元素。 序列或范围的末尾始终定义为最后一个元素的下一个位置。 全局函数 beginend 会将迭代器返回到指定容器。 典型显式迭代器循环访问容器中的所有元素,如下所示:

vector<int> vec{ 0,1,2,3,4 };
for (auto it = begin(vec); it != end(vec); it++)
{
    // Access element using dereference operator
    cout << *it << " ";
}

可以使用范围 for 循环更加简单地完成相同操作:

for (auto num : vec)
{
    // no dereference operator
    cout << num << " ";
}

有五种类别的迭代器。 这些类别如下所示(按功能逐渐增强的顺序):

  • 输出。 输出迭代器X可以使用运算符循环访问序列++,并且只能使用*运算符编写一次元素。

  • 输入。 输入迭代器X可以使用运算符循环访问序列++,并且可以使用*运算符读取元素任意次数。 可使用 ==!= 运算符来比较输入迭代器。 递增输入迭代器的任何副本后,无法安全地比较、取消引用或递增其他任何副本。

  • 转发转发迭代器X可以使用 ++ 运算符循环访问序列,并且可以使用运算符读取任何元素或写入非常量元素的次数*。 可使用 -> 运算符访问元素成员,使用 ==!= 运算符比较向前迭代器。 可以创建向前迭代器的多个副本,其中每个副本都可以独立地取消引用和递增。 未使用对任何容器的引用进行初始化的向前迭代器称为 null 向前迭代器。 Null 向前迭代器的比较结果始终是相等的。

  • 双向双向迭代器X可以取代向前迭代器。 但是,还可以递减双向迭代器例如在 --XX--(V = *X--) 中。 可以采用与向前迭代器相同的方式访问元素成员和比较双向迭代器。

  • 随机访问随机访问迭代器X可以取代双向迭代器。 借助随机访问迭代器,可以使用下标运算符 [] 访问元素。 可使用 +-+=-= 运算符向前或向后移动指定数量的元素并计算迭代器之间的距离。 可使用 ==!=<><=>= 比较双向迭代器。

可以分配或复制所有迭代器。 它们被假定为轻量对象,通常按值(而不是按引用)进行传递和返回。 另请注意,前面所述的操作都无法在对有效迭代器执行时引发异常。

可以通过显示三个序列来汇总迭代器类别的层次结构。 若要对序列进行只写访问,可以使用以下任何项:

输出迭代器
-> 向前迭代器
-> 双向迭代器
-> 随机访问迭代器

右箭头表示“可被替代为”。例如,为输出迭代器调用的任何算法应该都非常适合向前迭代器,而不是相反。

若要对序列进行只读访问,可以使用以下任何项:

输入迭代器
-> 向前迭代器
-> 双向迭代器
-> 随机访问迭代器

输入迭代器在这种情况下是所有类别中最弱的。

最后,若要对序列进行读/写访问,可以使用以下任何项:

向前迭代器
-> 双向迭代器
-> 随机访问迭代器

对象指针可以始终充当随机访问迭代器,因此如果它支持对它指定的序列进行正确的读/写访问,则它可以充当任何类别的迭代器。

对象指针以外的迭代器 Iterator 还必须定义专用化 iterator_traits<Iterator> 所需的成员类型。 可通过从公共基类 iterator 派生 Iterator 来满足这些需求。

请务必了解每个迭代器类别的承诺和限制,查看 C++ 标准库中的容器和算法如何使用迭代器。

注意

可以使用范围 for 循环来避免显式使用迭代器。 有关详细信息,请参阅基于范围的 for 语句

Microsoft C++ 现在提供经过检查的迭代器和调试迭代器,以确保不会覆盖容器的边界。 有关详细信息,请参阅经过检查的迭代器调试迭代器支持

另请参阅

C++ 标准库参考
C++ 标准库中的线程安全