跳转至

迭代器

在 STL 中,迭代器(Iterator)用來訪問和檢查 STL 容器中元素的對象,它的行為模式和指針類似,但是它封裝了一些有效性檢查,並且提供了統一的訪問格式。類似的概念在其他很多高級語言中都存在,如 Python 的 __iter__ 函數,C# 的 IEnumerator

基礎使用

迭代器聽起來比較晦澀,其實迭代器本身可以看作一個數據指針。迭代器主要支持兩個運算符:自增 (++) 和解引用(單目 * 運算符),其中自增用來移動迭代器,解引用可以獲取或修改它指向的元素。

指向某個 STL 容器 container 中元素的迭代器的類型一般為 container::iterator

迭代器可以用來遍歷容器,例如,下面兩個 for 循環的效果是一樣的:

1
2
3
4
5
6
7
8
vector<int> data(10);

for (int i = 0; i < data.size(); i++)
  cout << data[i] << endl;  // 使用下標訪問元素

for (vector<int>::iterator iter = data.begin(); iter != data.end(); iter++)
  cout << *iter << endl;  // 使用迭代器訪問元素
// 在C++11後可以使用 auto iter = data.begin() 來簡化上述代碼
auto 在競賽中的使用

大部分選手都喜歡使用 auto 來代替繁瑣的迭代器聲明。根據 2021 年 9 月發佈的 關於 NOI 系列活動中編程語言使用限制的補充説明,NOI 系列比賽(包括 CSP J/S)在評測時將使用 C++14,這個版本已經支持了 auto 關鍵字。

分類

在 STL 的定義中,迭代器根據其支持的操作依次分為以下幾類:

  • InputIterator(輸入迭代器):只要求支持拷貝、自增和解引訪問。
  • OutputIterator(輸出迭代器):只要求支持拷貝、自增和解引賦值。
  • ForwardIterator(向前迭代器):同時滿足 InputIterator 和 OutputIterator 的要求。
  • BidirectionalIterator(雙向迭代器):在 ForwardIterator 的基礎上支持自減(即反向訪問)。
  • RandomAccessIterator(隨機訪問迭代器):在 BidirectionalIterator 的基礎上支持加減運算和比較運算(即隨機訪問)。
  • ContiguousIterator(連續迭代器):在 RandomAccessIterator 的基礎上要求對可解引用的迭代器 a + n 滿足 *(a + n)*(std::address_of(*a) + n) 等價(即連續存儲,其中 a 為連續迭代器、n 為整型值)。

    ContiguousIterator 於 C++17 中正式引入。

為什麼輸入迭代器叫輸入迭代器?

「輸入」指的是「可以從迭代器中獲取輸入」,而「輸出」指的是「可以輸出到迭代器」。

「輸入」和「輸出」的施動者是程序的其它部分,而不是迭代器自身。

其實這個「分類」並不互斥——一個「類別」是可以包含另一個「類別」的。例如,在要求使用向前迭代器的地方,同樣可以使用雙向迭代器。

不同的 STL 容器 支持的迭代器類型不同,在使用時需要留意。

指針滿足隨機訪問迭代器的所有要求,可以當作隨機訪問迭代器使用。

相關函數

很多 STL 函數 都使用迭代器作為參數。

可以使用 std::advance(it, n) 將迭代器 it 向後移動 n 步;若 n 為負數,則對應向前移動。迭代器必須滿足雙向迭代器,否則行為未定義。

在 C++11 以後可以使用 std::next(it) 獲得向前迭代器 it 的後繼(此時迭代器 it 不變),std::next(it, n) 獲得向前迭代器 it 的第 n 個後繼。

在 C++11 以後可以使用 std::prev(it) 獲得雙向迭代器 it 的前驅(此時迭代器 it 不變),std::prev(it, n) 獲得雙向迭代器 it 的第 n 個前驅。

STL 容器 一般支持從一端或兩端開始的訪問,以及對 const 修飾符 的支持。例如容器的 begin() 函數可以獲得指向容器第一個元素的迭代器,rbegin() 函數可以獲得指向容器最後一個元素的反向迭代器,cbegin() 函數可以獲得指向容器第一個元素的 const 迭代器,end() 函數可以獲得指向容器尾端(「尾端」並不是最後一個元素,可以看作是最後一個元素的後繼;「尾端」的前驅是容器裏的最後一個元素,其本身不指向任何一個元素)的迭代器。

可在 Iterator library - cppreference.com 查看更多用法。