我正在尝试迭代std::list
但是存在问题 - 迭代期间执行的操作可能最终会从列表中添加或删除元素。在这种情况下,添加不是问题,但删除可能最终使列表中的任何迭代器无效,包括序列中的当前或下一项。
决定修改列表的点远离迭代循环 - 调试器在两者之间的调用堆栈中显示40个函数调用。因此,无法根据删除修改迭代器。
我唯一能想到的是在开始时制作列表的副本并对其进行迭代,测试每个元素以确保它仍然在主列表中。这是一个O(n ^ 2)命题,如果可能的话我想避免。
答案 0 :(得分:2)
您有三种选择:
当迭代器失效时重新开始(可能跳过n
次迭代?[与continue
])
编辑:
就像Pubby所说,标记删除的元素已过期,当你添加元素时使用跳过n
迭代的东西:)
迭代器不允许通过索引进行访问,因此这使得为您的问题提供优雅的解决方案变得更加困难。
答案 1 :(得分:1)
最终会使列表中的任何迭代器失效
不是。
查看std::list::erase
的{{3}}:
迭代器有效期
擦除结论:只有删除的元素才会变得无效。所有其他保持有效。而且,在这种情况下,您有机会在大多数情况下实现O(n)。
答案 2 :(得分:1)
以下是更多选项。
“修改”代码可以使用splice方法将其移动到某个临时列表,而不是删除元素。拼接单个元素是一个恒定的时间操作。并且它不会使任何迭代器或引用无效(即使对于移动的元素)。
在移动元素之前,“修改”代码应该推进列表迭代器的主副本(属于“迭代”代码)。
“迭代”代码应该在每次迭代后清除此临时列表。
优点: 无需向包含元素添加任何标记。
缺点: 由于需要清除临时列表而导致性能下降;需要外部接口来推进属于“迭代”代码的迭代器;如果“迭代”和“修改”代码之间的某些代码需要检查相对于“已删除”元素的下一个/前一个元素,它只会看到其他“已删除”元素而不是列表的其余部分。
如果为迭代器当前指向的元素设置“locked”标志,则“修改”代码可能仅对此单个元素使用拼接,并以通常方式删除其他元素。
“迭代”代码应该在每次迭代后清除临时列表。
优势: 几乎没有任何性能损失。
缺点: 需要修改列表的元素;需要外部接口来推进属于“迭代”代码的迭代器;如果“迭代”和“修改”代码之间的某些代码需要检查相对于“已删除”元素的下一个/前一个元素,则它找不到任何内容。
如果为迭代器当前指向的元素设置“locked”标志,则“修改”代码可能只为此单个元素设置“已删除”标志,并以通常方式删除其他元素。
“迭代”代码应该(在每次迭代之后)删除标记为要删除的元素。
优势: 几乎没有性能影响;如果“迭代”和“修改”代码之间的某些代码需要检查相对于“已删除”元素的下一个/前一个元素,它将按预期工作。
缺点: 需要修改列表元素。
答案 3 :(得分:0)
我想到了两种可能的方法(除了制作列表的副本外):
1)不要马上删除列表中的内容。相反,构建另一个迭代器容器,以便在完成所有迭代后完成擦除。这确实改变了行为("已删除的"元素仍然可以被采取行动)所以我不知道它是否对你有帮助。
2)让你的列表包含指针或带有项目/有效性标志的一对,并简单地清除有效性。然后,一旦你第一次完成迭代,再做一次迭代来清理退役节点。