我正在玩弄着解迭代器失效规则。但是,当我在c ++ 14编译器中运行以下代码时,输出确实让我感到困惑..
std::vector<int> test = {1,2,3};
auto it = test.begin() + 1;
test.erase(it);
std::cout << *it << std::endl;
输出= 3 在这一点上它不应该无效吗?为什么它似乎跳到下一个pos? 非常感谢提前
答案 0 :(得分:6)
取消引用无效的迭代器具有未定义的结果。您的程序可能会崩溃,它可能会因运行时错误或调试器中断而停止(如果您正在运行带有迭代器调试/验证的STL调试版本的调试版本)并且它可能“似乎工作”,即交付从集合中删除的值。
这是因为迭代器可以实现为指针。这不一定是这种情况,但在这种情况下将行为定义为未定义允许这种有效且简单的实现。作为指针实现的无效迭代器仍然可以指向一个有效的内存位置,它可能仍然包含它先前包含的值,即使它在逻辑上不再是它所属的数据结构(集合)的一部分。没有验证代码可以在解除引用时检查迭代器是否有效(有时在调试版本中除外)。
这既是C ++的特性优势之一,也是C ++的弱点之一,因为它可以在程序执行未定义的情况下(由于错误或使用未经验证的用户输入)以稳定性和安全性为代价为您的程序提供更好的性能)。
答案 1 :(得分:0)
在描述迭代器失效时,C ++标准采用迭代器引用元素的简化假设,有效迭代器值总是引用相同的元素。使元素的引用,指针或迭代器失效都遵循相同的规则。 (例外情况是结束迭代器)。
显然,对擦除元素的引用或指针被擦除调用无效,因此在标准的简单规则下,所有迭代器都是如此。它可以描述必须移动的新元素abd替换迭代器引用的内容,但是标准的编写者不会去那里。他们只是简单地指示迭代器是无效的。
因为它是无效的,所以取消引用它或做任何事情但是破坏它或为它分配anitger迭代器都被声明为未定义的行为。
理论上,这允许无数的优化机会,但我不知道任何利用它们的编译器。最好的编译器此时添加调试检查。
所以取消引用它&#34;工作&#34;,但是作为UB,结果是继承脆弱的。未来的编译器可能会假设您没有这样做并导致任意副作用,包括时间旅行(我不是在开玩笑;当前的编译器会导致UB计时并在UB发生之前损坏程序状态;特别是,int溢出优化)。
每个当前编译器最多使用包含在矢量迭代器中的精简指针。但是依赖于非标准强制执行的行为怪癖是一个糟糕的计划,当正确地执行它只需要更多的工作。如果您发现假设该行为非常有用的情况,我建议您使用您的用例作为动机来编写一个定义该行为的提议。