簡體   English   中英

C++11 中的尾端迭代器失效

[英]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 中,是否有任何容器操作可能使過去的迭代器無效,並且這種行為在語言規范中是模棱兩可的?

換個說法,

  • 在執行一個容器操作后,我是否可以相信一個過去迭代器的有效性,但它並沒有說它可能會使過去的迭代器失效?

我的問題是關於所有容器:

  • 在 C++11 中,是否有任何容器操作可能使過去的迭代器無效,並且這種行為在語言規范中是模棱兩可的?

我不確定您所說的“這種行為在語言規范中不明確的地方”是什么意思,但肯定有一些操作使過去的操作符無效(如插入std::vectorstd::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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM