迭代器
在 STL 中,迭代器(Iterator)用來訪問和檢查 STL 容器中元素的對象,它的行為模式和指針類似,但是它封裝了一些有效性檢查,並且提供了統一的訪問格式。類似的概念在其他很多高級語言中都存在,如 Python 的 __iter__ 函數,C# 的 IEnumerator。
基礎使用
迭代器聽起來比較晦澀,其實迭代器本身可以看作一個數據指針。迭代器主要支持兩個運算符:自增 (++) 和解引用(單目 * 運算符),其中自增用來移動迭代器,解引用可以獲取或修改它指向的元素。
指向某個 STL 容器 container 中元素的迭代器的類型一般為 container::iterator。
迭代器可以用來遍歷容器,例如,下面兩個 for 循環的效果是一樣的:
1 2 3 4 5 6 7 8 | |
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 查看更多用法。
本页面最近更新:,更新历史
发现错误?想一起完善? 在 GitHub 上编辑此页!
本页面贡献者:OI-wiki
本页面的全部内容在 CC BY-SA 4.0 和 SATA 协议之条款下提供,附加条款亦可能应用