C++ 上最受欢迎的帖子迭代器失效规则声称尚不清楚尾后迭代器(即由
end()
、cend()
、rend()
和 crend()
返回的迭代器)是否已失效按照与普通迭代器相同的规则,它指向容器中的元素。这些针对 2003 和 2011 C++ 的声明遵循了讨论“结束迭代器失效规则”的帖子,其中公认的答案表明 2003 年标准在这个问题上是不明确的。这个结论是基于 23.1/10 中的评论(在 swap()
的上下文中),该评论似乎暗示当规范没有明确提及尾后迭代器的失效时,它们可能会失效。 对该帖子问题的评论(作者 mike-seymour)表明,对于
deque
s 来说,C++11 在这个问题上是明确的。我的问题是关于所有容器的:
在 C++11 中,是否有任何容器操作可能会使尾后迭代器无效,并且这种行为在语言规范中的哪些地方是不明确的?
在执行容器操作后,我是否可以信任过去结束迭代器的有效性,但不会说它可能会使过去结束迭代器无效?
在 C++11 中,是否有任何容器操作可能会使尾后迭代器无效,以及这种行为在哪里是不明确的 语言规范?
我不确定“这种行为在语言规范中不明确的地方”是什么意思,但肯定有一些操作会使尾后迭代器无效(例如插入
std::vector
或
std::string
)。
换个说法,在执行容器操作后,我是否可以相信最后迭代器的有效性,但不会说它可能会失效 尾后迭代器?
您可以像任何其他迭代器一样信任尾后迭代器:任何不(可能)使迭代器无效的操作都不会使其无效。除了标准存在错误的可能性之外,这是所有没有说它们(可能)使运算符无效的操作。
尾后迭代器值得特别一提。一般来说,该迭代器会失效,就像它是非擦除元素的普通迭代器一样。因此 std::set::end 永远不会失效,std::unordered_set::end 仅在 rehash 时失效,std::vector::end 始终失效(因为它始终位于修改的元素之后),等等。
https://godbolt.org/z/5ecdqYod3有一个例外:删除 std::deque 的最后一个元素的擦除确实会使尾后迭代器无效,即使它不是容器的已擦除元素(或根本不是元素)。结合 std::deque 迭代器的一般规则,最终结果是唯一不会使 std::deque::end 无效的修改操作是擦除,它删除第一个元素,但不删除最后一个元素。
另请参阅 std::set 的 end() 测试 -
#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
}