在调试一些代码时,我发现迭代器的使用无效。所以我在我们的代码库中搜索了更多的错误用法。我发现了一些:
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++ );
就是你应该做的。这更令人困惑,因为:如果cppContainer
是std::vector
,cppContainer.erase( it++ );
会导致it
无效,而如果std::list
,it
仍然是好的。
仅使迭代器和对已擦除元素的引用无效。*
Ps。需要明确的是:it = cppContainer.erase( it );
是跨所有标准库容器执行此操作的规范且正确的方法。