[英]Past-the-end iterator invalidation in C++11
關於 C++迭代器失效規則的最受歡迎的帖子聲稱,不清楚過去的迭代器(即end()
、 cend( cend()
、 rend()
和crend()
返回的迭代器)是否根據與普通迭代器相同的規則,它們指向容器中的元素。 這些針對 2003 年和 2011 年 C++ 的聲明遵循討論End iterator invalidation rules的帖子,其中接受的答案表明 2003 年標准在此問題上模棱兩可。 這個結論是基於 23.1/10 中的評論(在swap()
的上下文中),這似乎暗示當規范沒有明確提到結束后迭代器的失效時,它們可能會失效。
對該帖子問題的評論(由 mike-seymour 撰寫)表明 C++11 在這個問題上是明確的,在deque
的情況下。 我的問題是關於所有容器:
換個說法,
我的問題是關於所有容器:
- 在 C++11 中,是否有任何容器操作可能使過去的迭代器無效,並且這種行為在語言規范中是模棱兩可的?
我不確定您所說的“這種行為在語言規范中不明確的地方”是什么意思,但肯定有一些操作使過去的操作符無效(如插入std::vector
或std::string
)。
換個說法,
- 在執行一個容器操作后,我是否可以相信一個過去迭代器的有效性,但它並沒有說它可能會使過去的迭代器失效?
您可以像任何其他迭代器一樣信任過去的迭代器:任何不會(可能)使迭代器無效的操作都不會使它們無效。 除了標准可能存在錯誤之外,所有操作都沒有說它們(可能)使操作員無效。
如果標准說該操作不會使迭代器無效,您應該能夠信任它。 其他任何東西都應該被視為標准庫實現中的錯誤。
至少在 GCC 結束迭代器對 std::map 無效:
#include <set>
#include <stdlib.h>
#include <assert.h>
int main() {
std::set<int> a;
a.insert(1);
std::set<int>::reverse_iterator rit(a.rbegin());
++rit;
assert(rit==a.rend());
a.erase(a.begin());
assert(a.rend()==rit); // FAIL
}
關於結束迭代器的失效規則,在cppreference.com#Iterator_invalidation中有提及。
相關線路是:
過去的迭代器值得特別提及。 一般來說,這個迭代器是無效的,就好像它是一個非擦除元素的普通迭代器。 所以 std::set::end 永遠不會失效, std::unordered_set::end 僅在 rehash 時失效, std::vector::end 總是失效(因為它總是在修改的元素之后),等等。
有一個例外:刪除 std::deque 的最后一個元素的擦除確實使過去的迭代器無效,即使它不是容器的已擦除元素(或根本不是元素)。 結合 std::deque 迭代器的一般規則,最終結果是唯一不會使 std::deque::end 無效的修改操作是刪除第一個元素而不是最后一個元素的擦除。
另請參閱 std::set 的 end() 測試 - https://godbolt.org/z/5ecdqYod3 。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.