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

问题描述 投票:0回答:4

C++ 上最受欢迎的帖子迭代器失效规则声称尚不清楚尾后迭代器(即由

end()
cend()
rend()
crend()
返回的迭代器)是否已失效按照与普通迭代器相同的规则,它指向容器中的元素。这些针对 2003 和 2011 C++ 的声明遵循了讨论“结束迭代器失效规则”的帖子,其中公认的答案表明 2003 年标准在这个问题上是不明确的。这个结论是基于 23.1/10 中的评论(在 swap() 的上下文中),该评论似乎暗示当规范没有明确提及尾后迭代器的失效时,它们可能会失效。

对该帖子问题的评论(作者 mike-seymour)表明,对于

deque

s 来说,C++11 在这个问题上是明确的。我的问题是关于所有容器的:


在 C++11 中,是否有任何容器操作可能会使尾后迭代器无效,并且这种行为在语言规范中的哪些地方是不明确的?
  • 换个说法,

在执行容器操作后,我是否可以信任过去结束迭代器的有效性,但不会说它可能会使过去结束迭代器无效?
c++ iterator
4个回答
13
投票
我的问题是关于所有容器的:

在 C++11 中,是否有任何容器操作可能会使尾后迭代器无效,以及这种行为在哪里是不明确的 语言规范?
我不确定“这种行为在语言规范中不明确的地方”是什么意思,但肯定有一些操作会使尾后迭代器无效(例如插入
std::vector

std::string
)。

换个说法,

在执行容器操作后,我是否可以相信最后迭代器的有效性,但不会说它可能会失效 尾后迭代器?
您可以像任何其他迭代器一样信任尾后迭代器:任何不(可能)使迭代器无效的操作都不会使其无效。除了标准存在错误的可能性之外,这是所有没有说它们(可能)使运算符无效的操作。


2
投票


1
投票
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

.


0
投票

#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 }

© www.soinside.com 2019 - 2024. All rights reserved.