迭代正在改变的std :: list的有效方法?

时间:2013-06-10 22:44:02

标签: c++ list iterator

我正在尝试迭代std::list但是存在问题 - 迭代期间执行的操作可能最终会从列表中添加或删除元素。在这种情况下,添加不是问题,但删除可能最终使列表中的任何迭代器无效,包括序列中的当前或下一项。

决定修改列表的点远离迭代循环 - 调试器在两者之​​间的调用堆栈中显示40个函数调用。因此,无法根据删除修改迭代器。

我唯一能想到的是在开始时制作列表的副本并对其进行迭代,测试每个元素以确保它仍然在主列表中。这是一个O(n ^ 2)命题,如果可能的话我想避免。

4 个答案:

答案 0 :(得分:2)

您有三种选择:

  1. 就像你说的那样制作一份列表的本地副本
  2. 当迭代器失效时重新开始(可能跳过n次迭代?[与continue])

  3. 编辑: 就像Pubby所说,标记删除的元素已过期,当你添加元素时使用跳过n迭代的东西:)

  4. 迭代器不允许通过索引进行访问,因此这使得为您的问题提供优雅的解决方案变得更加困难。

答案 1 :(得分:1)

  

最终会使列表中的任何迭代器失效

不是。

查看std::list::erase的{​​{3}}:

迭代器有效期

  • 引用删除的元素的迭代器,指针和引用 该功能无效。
  • 所有其他迭代器,指针和引用保持其有效性

擦除结论:只有删除的元素才会变得无效。所有其他保持有效。而且,在这种情况下,您有机会在大多数情况下实现O(n)。

答案 2 :(得分:1)

以下是更多选项。

1。拼接

“修改”代码可以使用splice方法将其移动到某个临时列表,而不是删除元素。拼接单个元素是一个恒定的时间操作。并且它不会使任何迭代器或引用无效(即使对于移动的元素)。

在移动元素之前,“修改”代码应该推进列表迭代器的主副本(属于“迭代”代码)。

“迭代”代码应该在每次迭代后清除此临时列表。

优点: 无需向包含元素添加任何标记。

缺点: 由于需要清除临时列表而导致性能下降;需要外部接口来推进属于“迭代”代码的迭代器;如果“迭代”和“修改”代码之间的某些代码需要检查相对于“已删除”元素的下一个/前一个元素,它只会看到其他“已删除”元素而不是列表的其余部分。

2。拼锁“锁定”标志

如果为迭代器当前指向的元素设置“locked”标志,则“修改”代码可能仅对此单个元素使用拼接,并以通常方式删除其他元素。

“迭代”代码应该在每次迭代后清除临时列表。

优势: 几乎没有任何性能损失。

缺点: 需要修改列表的元素;需要外部接口来推进属于“迭代”代码的迭代器;如果“迭代”和“修改”代码之间的某些代码需要检查相对于“已删除”元素的下一个/前一个元素,则它找不到任何内容。

3。 “锁定”和“删除”标志

如果为迭代器当前指向的元素设置“locked”标志,则“修改”代码可能只为此单个元素设置“已删除”标志,并以通常方式删除其他元素。

“迭代”代码应该(在每次迭代之后)删除标记为要删除的元素。

优势: 几乎没有性能影响;如果“迭代”和“修改”代码之间的某些代码需要检查相对于“已删除”元素的下一个/前一个元素,它将按预期工作。

缺点: 需要修改列表元素。

答案 3 :(得分:0)

我想到了两种可能的方法(除了制作列表的副本外):

1)不要马上删除列表中的内容。相反,构建另一个迭代器容器,以便在完成所有迭代后完成擦除。这确实改变了行为("已删除的"元素仍然可以被采取行动)所以我不知道它是否对你有帮助。

2)让你的列表包含指针或带有项目/有效性标志的一对,并简单地清除有效性。然后,一旦你第一次完成迭代,再做一次迭代来清理退役节点。