迭代器庫
迭代器是指標的推廣,它允許 C++ 程式以統一的方式處理不同的資料結構(例如容器和範圍(C++20 起))。迭代器庫提供了迭代器的定義,以及迭代器特性、介面卡和實用函式。
由於迭代器是指標的抽象,其語義是指標在 C++ 中大部分語義的推廣。這確保了所有接受迭代器的函式模板也適用於普通指標。
目錄 |
[編輯] 迭代器類別
迭代器有五(C++17 前)六(C++17 起)種:LegacyInputIterator、LegacyOutputIterator、LegacyForwardIterator、LegacyBidirectionalIterator、LegacyRandomAccessIterator,以及LegacyContiguousIterator(C++17 起)。(另請參見最基本迭代器型別LegacyIterator。)
每種迭代器類別不是由特定型別定義的,而是由可以在其上執行的操作定義的。此定義意味著任何支援必要操作的型別都可以用作迭代器——例如,指標支援LegacyRandomAccessIterator所需的所有操作,因此指標可以在任何期望LegacyRandomAccessIterator的地方使用。
所有迭代器類別(除了LegacyOutputIterator)都可以組織成一個層次結構,其中更強大的迭代器類別(例如LegacyRandomAccessIterator)支援較弱類別(例如LegacyInputIterator)的操作。如果迭代器屬於這些類別之一,並且還滿足LegacyOutputIterator的要求,那麼它被稱為“可變”迭代器,並支援輸入和輸出。不可變迭代器被稱為“常量”迭代器。
如果為滿足迭代器類別要求而提供的所有操作都是constexpr 函式,則迭代器被稱為constexpr迭代器。 |
(C++20 起) |
迭代器類別 | 操作和儲存要求 | ||||||
---|---|---|---|---|---|---|---|
寫入 | 讀取 | 遞增 | 遞減 | 隨機 訪問 |
連續 儲存 | ||
不帶 多次 傳遞 |
帶 多次 傳遞 | ||||||
LegacyIterator(傳統迭代器) | 必需 | ||||||
LegacyOutputIterator(傳統輸出迭代器) | 必需 | 必需 | |||||
LegacyInputIterator(傳統輸入迭代器) (如果支援寫入操作,則為可變) |
必需 | 必需 | |||||
LegacyForwardIterator(傳統前向迭代器) (也滿足LegacyInputIterator) |
必需 | 必需 | 必需 | ||||
LegacyBidirectionalIterator(傳統雙向迭代器) (也滿足LegacyForwardIterator) |
必需 | 必需 | 必需 | 必需 | |||
LegacyRandomAccessIterator(傳統隨機訪問迭代器) (也滿足LegacyBidirectionalIterator) |
必需 | 必需 | 必需 | 必需 | 必需 | ||
LegacyContiguousIterator[1] (也滿足LegacyRandomAccessIterator) |
必需 | 必需 | 必需 | 必需 | 必需 | 必需 |
- ↑ LegacyContiguousIterator類別僅在 C++17 中正式指定,但在 C++17 之前的程式碼中,std::vector、std::basic_string、std::array和std::valarray的迭代器,以及指向 C 陣列的指標通常被視為一個單獨的類別。
注意:支援上表一行中所需操作的型別不一定屬於相應的類別,完整要求列表請參見類別頁面。
[編輯] 定義
[編輯] 型別和可寫性
輸入迭代器i支援表示式*i,結果是某種物件型別T
的值,稱為迭代器的值型別。
輸出迭代器i擁有一組非空的型別,這些型別可寫入(C++20 前)indirectly_writable(C++20 起)到迭代器;對於每個這樣的型別T
,表示式*i = o是有效的,其中o是型別T
的值。
對於定義了相等性的每個迭代器型別X
,存在一個對應的有符號整型(C++20 前)類似整型(C++20 起)型別,稱為迭代器的差值型別。
[編輯] 解引用性與有效性
正如指向陣列的普通指標保證存在指向陣列最後一個元素之後位置的指標值一樣,對於任何迭代器型別,也存在一個指向相應序列最後一個元素之後位置的迭代器值。這樣的值稱為末尾後值。
對於迭代器i,如果表示式*i已定義,則稱其值為可解引用。 標準庫從不假定末尾後值是可解引用的。
迭代器也可以具有與任何序列不關聯的奇異值。大多數表示式的結果對於奇異值都是未定義的;唯一的例外是
- 將非奇異值賦值給持有奇異值的迭代器,
- 銷燬持有奇異值的迭代器,以及
- 對於滿足DefaultConstructible要求的迭代器,使用值初始化的迭代器作為複製或移動(C++11 起)操作的源。
在這些情況下,奇異值像任何其他值一樣被覆蓋。可解引用值總是非奇異的。
無效迭代器是可能為奇異的迭代器。
[編輯] 範圍
標準庫中大多數對資料結構進行操作的演算法模板都使用範圍作為介面。
迭代器j被稱為從迭代器i可達,當且僅當存在有限次應用表示式++i的序列,使得i == j。如果j可從i到達,則它們引用同一序列的元素。 範圍是一對迭代器,它們指定了計算的開始和結束。 範圍 |
(C++20 前) |
範圍可以由以下任一方式表示:
迭代器-哨兵範圍表示範圍的迭代器和哨兵是可比較的。 當且僅當存在有限次應用表示式++i的序列,使得i == s,則稱哨兵s從迭代器i可達。 如果s可從i到達,則 計數範圍計數範圍i 計數範圍i
|
(C++20 起) |
將標準庫中的函式應用於無效範圍的結果是未定義的。
[編輯] 迭代器概念 (C++20 起)
一個基於概念的全新迭代器系統,它與 C++17 迭代器不同。雖然基本分類保持相似,但各個迭代器類別的要求有所不同。
定義於名稱空間
std | |
(C++20) |
透過應用運算子* 指定型別是間接可讀的(概念) |
(C++20) |
指定值可以寫入迭代器引用的物件 (概念) |
(C++20) |
指定一個semiregular 型別可以使用前置和後置增量運算子進行增量操作(概念) |
(C++20) |
指定weakly_incrementable 型別上的增量操作是保持相等性的,並且該型別是equality_comparable 的(概念) |
(C++20)(C++20) |
指定型別行為類似(有符號)整型 (僅供說明的概念*) |
(C++20) |
指定型別物件可以被增量和解引用 (概念) |
(C++20) |
指定型別是input_or_output_iterator 型別的哨兵(概念) |
(C++20) |
指定-運算子可應用於迭代器和哨兵,以常數時間計算它們的差值 (概念) |
(C++20) |
指定型別是一個輸入迭代器,即其引用的值可讀,並且可以進行前置和後置增量 (概念) |
(C++20) |
指定型別是給定值型別的輸出迭代器,即該型別的值可以寫入其中,並且可以進行前置和後置增量 (概念) |
(C++20) |
指定input_iterator 是前向迭代器,支援相等比較和多趟遍歷(概念) |
(C++20) |
指定forward_iterator 是雙向迭代器,支援向後移動(概念) |
(C++20) |
指定一個 bidirectional_iterator 是一個隨機訪問迭代器,支援常數時間步進和下標操作(概念) |
(C++20) |
指定random_access_iterator 是連續迭代器,引用記憶體中連續的元素(概念) |
[編輯] 迭代器關聯型別 (C++20 起)
定義於名稱空間
std | |
(C++20) |
計算weakly_incrementable 型別的差值型別(類模板) |
(C++20) |
計算indirectly_readable 型別的值型別(類模板) |
(C++20)(C++20)(C++23)(C++20)(C++20)(C++20) |
計算迭代器的關聯型別 (別名模板) |
[編輯] 迭代器原語
提供迭代器屬性的統一介面 (類模板) | |
用於指示迭代器類別的空類型別 (類) | |
(C++17 中已棄用) |
基類,用於簡化簡單迭代器所需型別的定義 (類模板) |
[編輯] 迭代器定製點 (C++20 起)
定義於名稱空間
std::ranges | |
(C++20) |
將解引用物件的結果轉換為其關聯的右值引用型別 (定製點物件) |
(C++20) |
交換兩個可解引用物件所引用的值 (定製點物件) |
[編輯] 演算法概念和實用工具 (C++20 起)
一組概念和相關實用模板,旨在簡化對常見演算法操作的約束。
定義於標頭檔案
<iterator> | |
定義於名稱空間
std | |
間接可呼叫概念 | |
指定可呼叫型別可以使用解引用indirectly_readable 型別的結果進行呼叫(概念) | |
(C++20) |
指定可呼叫型別,當使用解引用indirectly_readable 型別的結果呼叫時,滿足predicate (概念) |
(C++20) |
指定可呼叫型別,當使用解引用兩個indirectly_readable 型別的結果呼叫時,滿足predicate (概念) |
指定可呼叫型別,當使用解引用兩個indirectly_readable 型別的結果呼叫時,滿足equivalence_relation (概念) | |
(C++20) |
指定可呼叫型別,當使用解引用兩個indirectly_readable 型別的結果呼叫時,滿足strict_weak_order (概念) |
常用演算法要求 | |
(C++20) |
指定值可以從indirectly_readable 型別移動到indirectly_writable 型別(概念) |
(C++20) |
指定值可以從indirectly_readable 型別移動到indirectly_writable 型別,並且該移動可以透過中間物件執行(概念) |
(C++20) |
指定值可以從indirectly_readable 型別複製到indirectly_writable 型別(概念) |
(C++20) |
指定值可以從indirectly_readable 型別複製到indirectly_writable 型別,並且該複製可以透過中間物件執行(概念) |
(C++20) |
指定兩個 indirectly_readable 型別所引用的值可以被交換(概念) |
(C++20) |
指定兩個indirectly_readable 型別引用的值可以比較(概念) |
(C++20) |
指定就地重新排序元素的演算法的共同要求 (概念) |
(C++20) |
指定透過複製元素將已排序序列合併到輸出序列中的演算法的要求 (概念) |
(C++20) |
指定將序列排列成有序序列的演算法的共同要求 (概念) |
工具 | |
(C++20) |
計算在解引用一組indirectly_readable 型別的結果上呼叫可呼叫物件的結果(別名模板) |
(C++20) |
用於指定接受投影的演算法約束的輔助模板 (類模板) |
(C++26) |
透過投影計算indirectly_readable 型別的值型別(別名模板) |
[編輯] 迭代器介面卡
用於反向遍歷的迭代器介面卡 (類模板) | |
(C++14) |
建立從引數推斷型別的std::reverse_iterator (函式模板) |
用於在容器末尾插入的迭代器介面卡 (類模板) | |
建立從引數推斷型別的std::back_insert_iterator (函式模板) | |
用於在容器前端插入的迭代器介面卡 (類模板) | |
建立從引數推斷型別的std::front_insert_iterator (函式模板) | |
用於在容器中插入的迭代器介面卡 (類模板) | |
建立從引數推斷型別的std::insert_iterator (函式模板) | |
(C++23) |
將迭代器轉換為常量迭代器的介面卡 (類模板) |
(C++23) |
為給定型別計算常量迭代器型別 (別名模板) |
(C++23) |
計算與常量迭代器一起使用的哨兵型別 (別名模板) |
(C++23) |
建立從引數推斷型別的std::const_iterator (函式模板) |
(C++23) |
建立從引數推斷型別的std::const_sentinel (函式模板) |
(C++11) |
解引用為右值的迭代器介面卡 (類模板) |
(C++20) |
std::move_iterator的哨兵介面卡 (類模板) |
(C++11) |
建立從引數推斷型別的std::move_iterator (函式模板) |
(C++20) |
將迭代器型別及其哨兵適配成一個通用迭代器型別 (類模板) |
(C++20) |
用於知道其範圍邊界的迭代器的預設哨兵 (類) |
(C++20) |
跟蹤到範圍末尾距離的迭代器介面卡 (類模板) |
(C++20) |
始終與任何weakly_incrementable 型別比較不相等的哨兵(類) |
[編輯] 流迭代器
從std::basic_istream讀取的輸入迭代器 (類模板) | |
寫入std::basic_ostream的輸出迭代器 (類模板) | |
從std::basic_streambuf讀取的輸入迭代器 (類模板) | |
寫入std::basic_streambuf的輸出迭代器 (類模板) |
[編輯] 迭代器操作
定義於標頭檔案
<iterator> | |
按給定距離前進迭代器 (函式模板) | |
返回兩個迭代器間的距離 (函式模板) | |
(C++11) |
遞增迭代器 (函式模板) |
(C++11) |
遞減迭代器 (函式模板) |
(C++20) |
將迭代器前進指定距離或到指定邊界 (演算法函式物件) |
(C++20) |
返回迭代器與哨兵之間,或範圍開頭與結尾之間的距離 (演算法函式物件) |
(C++20) |
按給定距離或到邊界遞增迭代器 (演算法函式物件) |
(C++20) |
按給定距離或到邊界遞減迭代器 (演算法函式物件) |
[編輯] 範圍訪問 (C++11 起)
這些非成員函式模板為容器、普通陣列和std::initializer_list提供了通用介面。
定義於標頭檔案
<array> | |
在標頭檔案
<deque> 中定義 | |
在標頭檔案
<flat_map> 中定義 | |
在標頭檔案
<flat_set> 中定義 | |
在標頭檔案
<forward_list> 中定義 | |
在標頭檔案
<inplace_vector> 中定義 | |
定義於標頭檔案
<iterator> | |
定義於標頭檔案
<list> | |
定義於標頭檔案
<map> | |
在標頭檔案
<regex> 中定義 | |
在標頭檔案
<set> 中定義 | |
在標頭檔案
<span> 中定義 | |
定義於標頭檔案
<string> | |
定義於標頭檔案
<string_view> | |
在標頭檔案
<unordered_map> 中定義 | |
定義於標頭檔案
<unordered_set> | |
在標頭檔案
<vector> 中定義 | |
定義於名稱空間
std | |
(C++11)(C++14) |
返回指向容器或陣列開頭的迭代器 (函式模板) |
(C++11)(C++14) |
返回指向容器或陣列末尾的迭代器 (函式模板) |
(C++14) |
返回指向容器或陣列開頭的反向迭代器 (函式模板) |
(C++14) |
返回容器或陣列的反向結束迭代器 (函式模板) |
(C++17)(C++20) |
返回容器或陣列的大小 (函式模板) |
(C++17) |
檢查容器是否為空 (函式模板) |
(C++17) |
獲取指向底層陣列的指標 (函式模板) |
[編輯] 缺陷報告
下列更改行為的缺陷報告追溯地應用於以前出版的 C++ 標準。
缺陷報告 | 應用於 | 釋出時的行為 | 正確的行為 |
---|---|---|---|
CWG 1181 | C++98 | 陣列型別不能是值型別 | 推導指引可以有尾隨的requires子句 |
LWG 208 | C++98 | 末尾後迭代器總是非奇異的 | 它們可以是奇異的 |
LWG 278 | C++98 | 迭代器的有效性未定義 | 定義為始終非奇異 |
LWG 324 | C++98 | 輸出迭代器具有值型別 | 輸出迭代器轉而具有可寫型別 |
LWG 407 | C++98 | 奇異迭代器不能被銷燬 | 允許 |
LWG 408 (N3066) |
C++98 | 奇異迭代器不能被複制 | 如果它們是值初始化的,則允許 |
LWG 1185 (N3066) |
C++98 | LegacyForwardIterator、LegacyBidirectionalIterator 和LegacyRandomAccessIterator 總是滿足LegacyOutputIterator |
它們可能不滿足LegacyOutputIterator |
LWG 1210 (N3066) |
C++98 | 迭代器奇異性和 可達性的定義依賴於容器 |
轉而依賴於序列 |
LWG 3009 | C++17 | <string_view>未提供 範圍訪問函式模板 |
提供這些模板 |
LWG 3987 | C++23 | <flat_map>和<flat_set>未 提供範圍訪問函式模板 |
提供這些模板 |