迭代可能从容器中移除自身的对象

时间:2015-07-07 11:16:25

标签: c++ iteration containers observer-pattern

如果在迭代期间可以删除对象,我如何安全地迭代容器?我基本上试图实现观察者模式,并且一些事件将导致从订阅容器中删除侦听器,这会导致迭代器出现问题。

我考虑过为每个听众提供一个标志,当它希望从订阅者列表中删除时,它可以设置一个标志。因此,不是侦听器直接删除自身,主题将在迭代期间检查标志,跳过标记的侦听器,并在完成发送通知后擦除所有标记的侦听器。

我考虑的另一个选项是为每次调用listener.notify启动一个线程,并使主题上的remove_listener方法成为互斥锁定操作。

第一个选项看起来很糟糕,因为使用标志来指示某个对象的状态往往会在整个程序中激增,很快每次处理对象时都需要检查if (!object.TO_BE_DELETED)类似于阻塞的问题来自空指针。

第二个选项带来了使用线程的所有麻烦,如果程序使用了很多事件,我很确定这会很快产生性能问题。

那么这个问题有什么更好的解决方案呢?

2 个答案:

答案 0 :(得分:2)

在从容器中删除元素后,你永远不应该使用相同的迭代器,因为迭代器会松散,你应该有迭代器的更新版本。例如,std :: list :: erase函数返回一个迭代器,指向被删除元素的下一个位置。

答案 1 :(得分:1)

没有迭代器:

for(int i = v.size() - 1; i >= 0; i--) {
    if(shouldDelete(v[i]))
        v.erase(v.begin() + i);
}

使用迭代器:

for(auto iter = v.begin(); iter != v.end(); ) {
    if(shouldDelete(*iter)) {
        iter = v.erase(iter);
    } else iter++;
}

在此上下文中不能使用range-for循环,因为删除元素会使所有迭代器无效,而range-for循环会在内部使用迭代器。

请注意,我在这里假设向量;如果您使用的是列表或集合,则只有迭代器方法才有效。 (这两种方法都适用于双端队列。)