迭代器程式庫
迭代器是 指標 的泛化,允許 C++ 程式與不同的資料結構(例如 容器 和 範圍(自 C++20 起))以統一的方式運作。迭代器函式庫提供了迭代器的定義,以及迭代器特性、轉接器和工具函式。
由於迭代器是指標的抽象,它們的語意是 C++ 中大多數指標語意的泛化。這確保了每個接受迭代器的 函式模板 也能與常規指標良好地運作。
目錄 |
[edit] 迭代器類別
迭代器有 五(直到 C++17)六(自 C++17 起)種類型:LegacyInputIterator、LegacyOutputIterator、LegacyForwardIterator、LegacyBidirectionalIterator、LegacyRandomAccessIterator,以及 LegacyContiguousIterator(自 C++17 起)。(另請參閱 LegacyIterator 以了解最基本類型的迭代器。)
迭代器類別並非由特定型別定義,而是由可在其上執行的操作來定義。這種定義方式意味著任何支援必要操作的型別都可以用作迭代器——例如,指標支援 LegacyRandomAccessIterator 所要求的所有操作,因此指標可以用在任何預期 LegacyRandomAccessIterator 的地方。
所有迭代器類別(LegacyOutputIterator 除外)都可以組織成一個階層,其中功能更強大的迭代器類別(例如 LegacyRandomAccessIterator)支援功能較弱類別(例如 LegacyInputIterator)的操作。如果一個迭代器屬於這些類別之一,並且也滿足 LegacyOutputIterator 的要求,那麼它被稱為可變的 (mutable) 迭代器,並同時支援輸入和輸出。不可變的迭代器稱為常數 (constant) 迭代器。
|
如果所有用於滿足迭代器類別要求的操作都是 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 陣列的指標,通常被視為一個單獨的類別。
注意:支援上表中某一行所需操作的型別不一定屬於相應的類別,請參閱類別頁面以獲取完整的需求列表。
[edit] 定義
[edit] 型別與可寫性
輸入迭代器 i 支援表達式 *i,其結果為某個 物件型別 T 的值,此 T 稱為該迭代器的值型別 (value type)。
輸出迭代器 i 具有一個非空的型別集合,這些型別對迭代器來說是 可寫入的 (writable)(直到 C++20)indirectly_writable(自 C++20 起);對於每個此類型的 T,表達式 *i = o 都是有效的,其中 o 是型別 T 的值。
對於每個定義了等價性的迭代器型別 X (直到 C++20),都有一個對應的帶符號 整數(直到 C++20)整數類 (integer-like)(自 C++20 起)型別,稱為迭代器的差異型別 (difference type)。
[edit] 解參照能力與有效性
正如指向 陣列 的常規指標保證存在一個指向陣列末尾後一個元素的指標值一樣,任何迭代器型別也存在一個指向相應序列末尾後一個元素的迭代器值。此類值稱為末端後 (past-the-end) 值。
對於迭代器 i,若表達式 *i 有定義,則該迭代器值稱為可解參照的 (dereferenceable)。標準函式庫 從不假設末端後值是可解參照的。
迭代器也可以具有奇異 (singular) 值,這些值不與任何序列關聯。大多數表達式的結果對於奇異值來說是未定義的;唯一的例外是
- 將非奇異值賦予持有奇異值的迭代器,
- 銷毀持有奇異值的迭代器,以及,
- 對於滿足 DefaultConstructible 要求的迭代器,使用 值初始化 的迭代器作為複製 或移動(自 C++11 起)操作的來源。
在這些情況下,奇異值會以與任何其他值相同的方式被覆寫。可解參照的值總是會是非奇異的。
無效 (invalid) 迭代器是指可能為奇異的迭代器。
[edit] 範圍
標準函式庫中大多數操作資料結構的演算法模板都採用了使用範圍的介面。
|
迭代器 j 被稱為可從迭代器 i 抵達 (reachable),當且僅當存在有限次應用表達式 ++i 使 i = = j。如果 j 可從 i 抵達,則它們參照的是同一序列中的元素。 範圍 (range) 是一對迭代器,用於指定計算的起點和終點。範圍 範圍 |
(直到 C++20) |
|
範圍可以由以下兩種方式之一表示:
迭代器-哨兵範圍表示範圍的迭代器和哨兵是可比較的。如果 i = = s,則 哨兵 s 被稱為可從迭代器 i 抵達,當且僅當存在有限次應用表達式 ++i 使 i = = s。 如果 s 可從 i 抵達,則 計數範圍計數範圍 (counted range) i 計數範圍 i
|
(自 C++20 起) |
標準函式庫中函式應用於無效範圍的結果是未定義的。
[edit] 迭代器概念 (自 C++20 起)
一套基於概念的新迭代器系統,與 C++17 迭代器有所不同。雖然基本分類仍然相似,但各個迭代器類別的要求有些不同。
| 定義於命名空間
std | |
| (C++20) |
指定某型別可透過套用運算子 * 進行間接讀取(概念) |
| (C++20) |
指定一個值可以寫入迭代器所參照的物件 (概念) |
| (C++20) |
指定一個 semiregular 型別可以透過前置與後置遞增運算子進行遞增(概念) |
| (C++20) |
指定 weakly_incrementable 型別的遞增操作是 相等性保留的 (equality-preserving),且該型別是 equality_comparable 的(概念) |
| (C++20)(C++20) |
指定一個型別表現得像一個(帶符號)整數型別 (僅作說明用的概念*) |
| (C++20) |
指定該型別的物件可以進行遞增與解參照 (概念) |
| (C++20) |
指定某型別是 input_or_output_iterator 型別的哨兵 (sentinel)(概念) |
| (C++20) |
指定 - 運算子可以應用於迭代器和哨兵,以常數時間計算它們的差異 (概念) |
| (C++20) |
指定一個型別為輸入迭代器 (input iterator),即其參照值可以讀取,且它可以進行前置與後置遞增 (概念) |
| (C++20) |
指定一個型別為給定值型別的輸出迭代器 (output iterator),即該型別的值可以寫入其中,且它可以進行前置與後置遞增 (概念) |
| (C++20) |
指定一個 input_iterator 是前向迭代器,支援相等性比較與多遍式 (multi-pass)(概念) |
| (C++20) |
指定一個 forward_iterator 是雙向迭代器,支援向後移動(概念) |
| (C++20) |
指定一個 bidirectional_iterator 是隨機存取迭代器,支援在常數時間內前進以及下標運算(概念) |
| (C++20) |
指定一個 random_access_iterator 是連續迭代器,其指向的元素在記憶體中是連續排列的(概念) |
[edit] 迭代器關聯型別 (自 C++20 起)
| 定義於命名空間
std | |
| (C++20) |
計算 weakly_incrementable 型別的差值型別 (difference type)(類別模板) |
| (C++20) |
計算 indirectly_readable 型別的值型別 (value type)(類別模板) |
| (C++20)(C++20)(C++23)(C++20)(C++20)(C++20) |
計算迭代器的關聯型別 (別名模板) |
[edit] 迭代器基本型別
| 提供存取迭代器屬性的統一介面 (類別模板) | |
| 用於指示迭代器類別的空類別型別 (類別) | |
| (C++17 中已廢棄) |
基礎類別,用以簡化簡單迭代器所需型別之定義 (類別模板) |
[edit] 迭代器自訂點 (自 C++20 起)
| 定義於命名空間
std::ranges | |
| (C++20) |
將解參照一個物件的結果轉型為其關聯的右值參照型別 (定制點物件) |
| (C++20) |
交換兩個可解引用物件所引用的值 (定制點物件) |
[edit] 演算法概念與工具 (自 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) |
用於指定接受投影 (projections) 的演算法約束之輔助模板 (類別模板) |
| (C++26) |
透過投影 (projection) 計算 indirectly_readable 型別的值型別(別名模板) |
[edit] 迭代器轉接器
| 用於逆序走訪的迭代器配接器 (類別模板) | |
| (C++14) |
建立一個型別由引數推導而來的 std::reverse_iterator (函式模板) |
| 用於在容器末尾插入元素的迭代器配接器 (類別模板) | |
| 建立一個型別由引數推導而來的 std::back_insert_iterator (函式模板) | |
| 用於在容器端頭插入元素的迭代器配接器 (類別模板) | |
| 建立一個型別由引數推導而來的 std::front_insert_iterator (函式模板) | |
| 用於在容器中插入元素的迭代器配接器 (類別模板) | |
| 建立一個型別由引數推導而來的 std::insert_iterator (函式模板) | |
| (C++23) |
將迭代器轉換為常數迭代器 (constant iterator) 的迭代器適配器 (類別模板) |
| (C++23) |
為給定型別計算常數迭代器型別 (別名模板) |
| (C++23) |
計算與常數迭代器一同使用的哨兵型別 (別名模板) |
| (C++23) |
建立一個從引數推斷型別的 std::const_iterator (函式模板) |
| (C++23) |
建立一個從引數推斷型別的 std::const_sentinel (函式模板) |
| (C++11) |
解引用為右值 (rvalue) 的迭代器適配器 (類別模板) |
| (C++20) |
用於 std::move_iterator 的哨兵適配器 (類別模板) |
| (C++11) |
建立一個型別由引數推導而來的 std::move_iterator (函式模板) |
| (C++20) |
將迭代器型別及其哨兵適配為通用迭代器 (common iterator) 型別 (類別模板) |
| (C++20) |
用於知道其範圍邊界的迭代器的預設哨兵 (類別) |
| (C++20) |
追蹤與範圍末端距離的迭代器適配器 (類別模板) |
| (C++20) |
總是與任何 weakly_incrementable 型別比較不等的哨兵(類別) |
[edit] 串流迭代器
| 從 std::basic_istream 讀取的輸入迭代器 (類別模板) | |
| 向 std::basic_ostream 寫入的輸出迭代器 (類別模板) | |
| 從 std::basic_streambuf 讀取的輸入迭代器 (類別模板) | |
| 向 std::basic_streambuf 寫入的輸出迭代器 (類別模板) |
[edit] 迭代器操作
| 定義於標頭檔
<iterator> | |
| 將迭代器推進給定的距離 (函式模板) | |
| 傳回兩個迭代器之間的距離 (函式模板) | |
| (C++11) |
遞增迭代器 (函式模板) |
| (C++11) |
遞減迭代器 (函式模板) |
| (C++20) |
將迭代器前進指定的距離或到指定的邊界 (演算法函式物件) |
| (C++20) |
傳回迭代器與哨兵之間,或範圍起點與終點之間的距離 (演算法函式物件) |
| (C++20) |
將迭代器遞增指定的距離或到一個邊界 (演算法函式物件) |
| (C++20) |
將迭代器遞減指定的距離或到一個邊界 (演算法函式物件) |
[edit] 範圍存取 (自 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) |
取得指向底層陣列的指標 (函式模板) |
[edit] 缺陷報告
下列更改行為的缺陷報告追溯應用於之前的 C++ 標準。
| DR | 應用於 | 出版時的行為 | 正確的行為 |
|---|---|---|---|
| CWG 1181 | C++98 | 陣列型別不能是值型別 | 它們可以 |
| 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> 未 提供範圍存取函式模板 |
提供了這些模板 |