天天看點

疊代器

與容器一樣,疊代器有着公共的接口,如果一個疊代器提供某個操作,那麼所有提供相同操作的疊代器對這個操作的實作方式都是相同的。例如,标準容器類型上的所有疊代器都允許我們通路容器中的元素,而所有疊代器都是通過解引用運算符來實作這個操作的。類似的,标準庫容器的所有疊代器都定義了遞增運算符,從目前元素移動到下一個元素。

下表列出了所有容器都支援的操作(除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的,而不管容器的類型是什麼。

繼續閱讀