在容器擦除过程中增加迭代器总是一个错误吗



在调试一些代码时,我发现迭代器的使用无效。所以我在我们的代码库中搜索了更多的错误用法。我发现了一些:

it = cppContainer.erase( it++ );

(其中it是此行之前的有效容器迭代器,cppContainer是STL容器,例如向量(。

这引发了一场讨论,讨论it++是否只是冗余的,或者在对容器.erase()的调用使迭代器无效后,它是否在对迭代器进行后增量,这将是

这个表单总是一个bug吗?显然++是不必要的,但它错了吗?

工程师们的普遍共识是,这是潜在的坏。

,或者在调用容器.erase()使迭代器无效后,它是否在对迭代器进行后增量。

请注意,在调用函数之前,参数会被完全求值。你可以从概念上想象后增量如下:

auto operator++(int) {
auto cp = *this;
++*this;
return cp;
}

如您所见,增量是在调用erase函数之前完成的;因此,这不是未定义的,但可能效率低下。

唯一未定义的方法是it++本身已经未定义。例如,it是结束迭代器,或者它已经无效,等等。

以下是我认为可以/应该解决的问题:

  • it++这会增加迭代器并返回旧值,并且在erase之前完成。这是可以的——除非it == end(或it无效(,否则它就是UB。

  • 但是递增充其量是毫无意义的,因为std::vector上的erase

在擦除*点或之后使迭代器和引用无效

  • 但是,在it之后立即被覆盖,这样就没有人可以使用现在无效的迭代器

因此,增量是毫无意义的,而且可以说是危险的,因为它可能会让人认为赋值是不必要的,而cppContainer.erase( it++ );就是你应该做的。这更令人困惑,因为:如果cppContainerstd::vectorcppContainer.erase( it++ );会导致it无效,而如果std::listit仍然是好的。

仅使迭代器和对已擦除元素的引用无效。*

Ps。需要明确的是:it = cppContainer.erase( it );是跨所有标准库容器执行此操作的规范且正确的方法。

相关内容

最新更新