我有一组迭代的对象,但是我可以在迭代期间决定现在需要删除其中一个(或多个)对象。
我的代码如下:
if( ! m_Container.empty() )
{
for( typedefedcontainer::iterator it = m_Container.begin();
it != m_Container.end();
++it )
{
if( ! ( SomeFunction( (*it), "test", "TEST!", false )) )
{
// If function returns false, delete object.
m_Container.erase( it );
AsyncResponseStore::iterator it = m_asyncResponses.begin();
}
}
}
但是当然,当我擦除一个对象时,我得到一个错误:“Map / set iterator not incrementable”。有人可以建议一个更好的方法吗?
请参阅: What happens if you call erase() on a map element while iterating from begin to end?
答案 0 :(得分:6)
这取决于容器。列表容器支持在枚举期间删除,方法是从erase方法返回一个新的迭代器,该方法表示列表中的下一个项目。地图不支持此。
一种简单的map方法是在单独的列表中累积要删除的项目,然后在完成地图处理以从地图中删除项目后迭代该列表。这假定您可以推迟删除,直到迭代完成。如果没有,那么你别无选择,只能为每次删除重新开始迭代。
答案 1 :(得分:6)
如果容器支持它(我怀疑你的容器不支持,但问题标题是通用的,所以如果不是你这可能对其他人有用):
struct SomePredicate {
bool operator()(typedefedcontainer::value_type thing) {
return ! SomeFunction(thing, "test", "TEST", false);
}
};
typedefedcontainer::iterator it;
it = std::remove_if(m_Container.begin(), m_Container.end(), SomePredicate());
m_Container.erase(it, m_Container.end());
m_Container必须具有擦除范围方法,该方法包括任何序列或关联容器。它确实必须有一个可变的迭代器,我只是注意到我最初误读了错误信息:它说“map / set iterator not incrementable”。所以我猜你的容器是一张地图或一套。
请注意,最后三个可能是一个真正奇妙的单行,但这个边距太窄而无法容纳它。
另外SomePredicate可以有一个带参数的构造函数来将其他参数存储到SomeFunction,因为在现实生活中我猜它们是非常量的。
如果你使用boost:bind构建函子,你实际上可以完全摆脱SomePredicate。那么你的单行将是真正庞大的。
[编辑:Rob Walker在他的回答中正确地指出了我在这里做出的假设并且问题没有说明,即所有擦除都可以推迟到迭代测试完成之后。如果SomeFunction通过隐藏路由访问m_Container(例如全局,或者因为SomeFunction实际上是其成员函数),并且其结果取决于容器的内容,那么我的代码可能与提问者的代码不同。但我认为我的代码是“除非有理由不”默认。]
答案 2 :(得分:0)
修正如下:
for( typedefedcontainer::iterator it = m_Container.begin();
it != m_Container.end();
)
{
if( ! ( SomeFunction( (*it), "test", "TEST!", false )) )
{
// If function returns false, delete object.
m_Container.erase( it++ );
}
else
{
++i;
}
}
删除元素时,所有指向它的指针都将失效。因此,通过使用它,我们可以解决它。感谢那些发布建议的人。