迭代器

与容器一样,迭代器有着公共的接口,如果一个迭代器提供某个操作,那么所有提供相同操作的迭代器对这个操作的实现方式都是相同的。例如,标准容器类型上的所有迭代器都允许我们访问容器中的元素,而所有迭代器都是通过解引用运算符来实现这个操作的。类似的,标准库容器的所有迭代器都定义了递增运算符,从当前元素移动到下一个元素。

下表列出了所有容器都支持的操作(除forward_list迭代器不支持--)

标准容器迭代器的运算符

*iter        返回迭代器iter所指元素的引用

iter->mem     解引用iter并获取该元素的名为mem的成员,等价于(*iter).mem

++iter       令iter指示容器的下一个元素

--iter         令iter指示容器中的上一个元素

iter1==iter2    判断两个迭代器是否相等(不相等),如果两个迭代器指示的是同一元素或者它们是同一容器的尾后迭代器则相等;反正,不相等

iter1!=iter2       

所有的容器都支持上面容器迭代器支持的所有操作,其中有一个例外不符合公共接口特点——forward_list迭代器不支持递减运算符(--)

下表列出了只适用于string、vector、deque和array的迭代器操作:

迭代器的递增运算令迭代器每次移动一个元素,所有的标准库容器都支持递增运算的迭代器。类似的,也能用==和!=对任意标准库类型的两个有效迭代器进行比较。

string和vector的迭代器提供了更多额外的运算符,一方面可使得迭代器的每次移动跨过多个元素,另外也支持迭代器进行关系运算符。所有这些运算被称作迭代器运算。

vector和string迭代器支持的运算

iter+n      迭代器加上一个整数值仍得一个迭代器,迭代器指示的新位置与原来相比向前移动了若干个元素。结果迭代器或者指示容器内的一个元素,或者指示容器                                           尾元素的下一个位置

iter-n      迭代器减去一个整数值仍得一个迭代器,迭代器指示的新位置与原来相比向后移动了若干个元素,结果迭代器或者指示容器内的一个元素,或者指示容器尾                                元素的下一个位置

iter1+=n    迭代器加法的复合赋值语句,将iter1加n的结果赋给iter1

iter1-=n     迭代器减法的复合赋值语句,将iter1减n的结果赋给iter1

iter1-iter2       两个迭代器相减的结果是它们之间的距离,也就是说,将运算符右侧的迭代器向前移动差值个元素后将得到左侧的迭代器。参与运算的两个迭代器必须指向的                       是同一个容器中的运算或者尾元素的下一个位置

> >= < <=       迭代器的关系运算符,如果某迭代器指向的容器位置在另一个迭代器所指位置之前,则说明前者小于后者,参与运算的两个迭代器必须指向的是同一个容器中的         元素或者尾元素的下一个位置

上面列出的所有支持的算术运算,这些运算只能应用于string、vector、deque和array的迭代器。我们不能将它们用于其他任何类型的迭代器

迭代器范围

一个迭代器范围是由一对迭代器表示,两个迭代器分别指向同一个容器中的元素或者是尾元素之后的位置。这两个迭代器通常被称为begin和end,或者是first和last,它们标记了容器中元素的一个范围。

这种元素范围被称为左闭合区间,其标准数学描述为

[begin,end)

表示范围自begin开始,于end之前结束。迭代器begin和end必须指向相同的容器。end可以与begin指向相同的位置,但不能指向begin之前的位置。

使用左闭合范围的编程假定

标准库使用左闭合范围是因为这种范围有三种方便的性质。假定begin和end构成一个合法的迭代器范围,则

  • 如果begin与end相等,则范围为空
  • 如果begin与end不等,则范围至少包含一个元素,且begin指向该范围中的第一个元素
  • 我们可以对begin递增若干次,使得begin==end

容器类型成员

每个容器都定义了多个类型,如下表所示,我们已经使用过其中的三种:size_type、iterator和const_iterator.

除了已经使用过的迭代器类型,大多数容器还提供了反向迭代器。简单地说,反向迭代器就是一种反向遍历容器的迭代器,与正向迭代器相比,各种操作的含义也都发生了颠倒。例如,对一个反向迭代器执行++操作,会得到上一个元素。

 类型别名:通过类型别名,我们可以在不了解容器中元素类型的情况下使用它。如果需要元素类型,可以使用容器的value_type如果需要元素类型的一个引用,可以使用reference或const reference。这些元素相关的类型别名在泛型编程中非常有用。

为了使用这些类型,我们必须显式使用其类名:

//iter是通过list<string> 定义的一个迭代器类型

list<string>::iterator iter;

//count是通过vector<int>定义的一个difference_type类型

vector<int>::difference_type count;

这些声明语句使用了作用域运算符来说明我们希望使用list<string>类的iterator成员及vector<int>类定义的difference_type。

begin和end成员

begin和end操作生成指向容器中第一个元素和尾元素之后位置的迭代器。这两个迭代器最常见的用途是形成一个包含容器中所有元素的迭代器范围。

begin和end有多个版本:带r的版本返回反向迭代器;带c的版本则返回const迭代器:

list<string> a={"Milton","Shakespeare","Austen"};

auto it1=a.begin(); //list<string>::iterator

auto it2=a.rbegin(); //list<string>::reverse_iterator

auto it3=a.cbegin(); //list<string>::const_iterator

auto it4=a.crbegin(); //list<string>::const_reverse_iterator

不以c开头的函数都是被重载果的。也就是说,实际上有两个名为begin 的成员。一个是const成员,返回容器的const_iterator类型。另一个是非常量成员,返回容器的iterator类型。rbegin、end和rend的情况类似。当我们对一个const对象调用这些函数时,才会得到一个const版本。与const指针和引用类似,可以将一个普通的iterator转换为对应的const_iterator,但反之不行。

以c开头的版本是C++新标准引入的,用支持auto与begin和end函数结合使用。过去,没有其他选择,只能显示声明希望使用哪种类型的迭代器:

//显式指定类型

list<string>::iterator it5=a.begin();

list<string>::const_iterator it6=a.begin();

//是iterator还是const_iterator依赖于a的类型

auto it7=a.begin() ; //仅当a是const时,it7是const_iterator

auto it8=a.cbegin(); //it8是const_iterator

当auto与begin或end结合使用时,获得的迭代器类型依赖于容器类型,与我们想要如何使用迭代器毫不相干。但以c开头的版本还是可以获得const_iterator的,而不管容器的类型是什么。

原文地址:https://www.cnblogs.com/wuchanming/p/3915552.html