避免迭代器在向量迭代期间失效

时间:2012-12-10 13:20:20

标签: c++

在迭代向量时,建议的避免错误的方法有哪些;向量中的任何数量的元素可能(直接地或间接地)导致元素的插入或删除 - 使迭代器无效?

具体来说,我要求与游戏编程有关,向量中的元素是游戏对象;其中一些可以产生其他对象,其中一些将被杀死,并在更新时需要删除。因此,在迭代之前保留大容量也是不可能的,因为完全不知道可以添加多少元素。

5 个答案:

答案 0 :(得分:3)

一般来说,这是不可能的。迭代器失效的原因的部分是没有办法读懂你的想法,知道你希望失效的迭代器引用哪个元素。

例如,我有一个5的元素3的迭代器。我擦除元素2.迭代器是否指向新元素2(因为它是“向下移动的相同值”),或者它应该指向新元素3(因为它是“具有不同值的向量的相同元素向下移动”)?

实际上,您的选择是:

  1. 当其他人拥有迭代器时,不要插入/擦除元素。这意味着更改代码以在其他时间进行更改。
  2. 使用索引而不是迭代器。这导致上面的第二个选项(“索引引用具有新值的相同元素”)。请注意,如果删除了足够的元素以使索引不在最后,索引也会变得无效。
  3. 使用具有不同迭代器失效规则的不同数据结构。例如,std::list将为您提供上面的第一个选项(“迭代器引用新位置中的相同元素”)
  4. 您用于迭代的迭代器永远不会因该位置的单个元素的插入/擦除而无效。它无效,但两个函数都返回一个可用于继续迭代的新迭代器。请参阅他们的文档,了解新迭代器引用的元素。这就是为什么只有当你在同一个容器上使用多个迭代器时才会出现这个问题。

答案 1 :(得分:1)

Vector可能不是支持密集插入/删除的最佳容器(特别是当大小很大时)。 但是如果你必须使用向量,恕我直言,最安全的方法是不使用迭代器而是使用索引并在当前位置之前跟踪(并调整索引)正在插入/删除的项目。这样您至少可以避免重新分配的问题。

每次迭代后重新计算v.size()/ v.end()。

答案 2 :(得分:1)

以下是一些想法:

  1. 使用整数索引迭代向量。这不会失效,但在插入/删除元素时需要注意调整当前索引。
  2. 迭代矢量副本。
  3. 不要在进行时对矢量进行更改,而是跟踪需要插入/删除的内容,并在完成迭代后应用更改。
  4. 使用其他容器,例如链接列表。

答案 3 :(得分:0)

使用单独的向量和std::move不会被删除的元素以及任何创建的新元素。然后放下旧矢量。

这样您就不必从原始向量中移除/插入任何内容,并且迭代器不会失效。

答案 4 :(得分:0)

当然,您可以使用一个容器来解决问题,该容器在插入和删除时不会使迭代器失效。

我想推荐一种不同的方法。基本上你是在迭代矢量来创建游戏世界中的新状态。在遍历矢量时,不是改变世界的状态,而是在新的矢量中存储需要改变的东西。然后,在完全检查旧状态后,应用存储在新矢量中的更改。

这种方法有一个概念上的优势:每个对象的新状态都取决于旧状态。如果在遍历旧状态时应用更改,并且有关一个对象的决策可能依赖于其他对象,则遍历的顺序可能会影响结果,这会使“早期”或“更晚”的对象成为不公平的优势。