std :: vector :: erase()是否真的使擦除点处的迭代器无效?

时间:2017-08-18 14:06:39

标签: c++ c++11 vector iterator

我正在玩弄着解迭代器失效规则。但是,当我在c ++ 14编译器中运行以下代码时,输​​出确实让我感到困惑..

std::vector<int> test = {1,2,3};
auto it = test.begin() + 1;
test.erase(it);
std::cout << *it << std::endl;

输出= 3 在这一点上它不应该无效吗?为什么它似乎跳到下一个pos? 非常感谢提前

2 个答案:

答案 0 :(得分:6)

取消引用无效的迭代器具有未定义的结果。您的程序可能会崩溃,它可能会因运行时错误或调试器中断而停止(如果您正在运行带有迭代器调试/验证的STL调试版本的调试版本)并且它可能“似乎工作”,即交付从集合中删除的值。

这是因为迭代器可以实现为指针。这不一定是这种情况,但在这种情况下将行为定义为未定义允许这种有效且简单的实现。作为指针实现的无效迭代器仍然可以指向一个有效的内存位置,它可能仍然包含它先前包含的值,即使它在逻辑上不再是它所属的数据结构(集合)的一部分。没有验证代码可以在解除引用时检查迭代器是否有效(有时在调试版本中除外)。

这既是C ++的特性优势之一,也是C ++的弱点之一,因为它可以在程序执行未定义的情况下(由于错误或使用未经验证的用户输入)以稳定性和安全性为代价为您的程序提供更好的性能)。

答案 1 :(得分:0)

在描述迭代器失效时,C ++标准采用迭代器引用元素的简化假设,有效迭代器值总是引用相同的元素。使元素的引用,指针或迭代器失效都遵循相同的规则。 (例外情况是结束迭代器)。

显然,对擦除元素的引用或指针被擦除调用无效,因此在标准的简单规则下,所有迭代器都是如此。它可以描述必须移动的新元素abd替换迭代器引用的内容,但是标准的编写者不会去那里。他们只是简单地指示迭代器是无效的。

因为它是无效的,所以取消引用它或做任何事情但是破坏它或为它分配anitger迭代器都被声明为未定义的行为。

理论上,这允许无数的优化机会,但我不知道任何利用它们的编译器。最好的编译器此时添加调试检查。

所以取消引用它&#34;工作&#34;,但是作为UB,结果是继承脆弱的。未来的编译器可能会假设您没有这样做并导致任意副作用,包括时间旅行(我不是在开玩笑;当前的编译器会导致UB计时并在UB发生之前损坏程序状态;特别是,int溢出优化)。

每个当前编译器最多使用包含在矢量迭代器中的精简指针。但是依赖于非标准强制执行的行为怪癖是一个糟糕的计划,当正确地执行它只需要更多的工作。如果您发现假设该行为非常有用的情况,我建议您使用您的用例作为动机来编写一个定义该行为的提议。