这个问题已被多次询问,但我的情况略有不同.假设我有一个观察者的std :: vector,当某个事件发生时我会通知它:
void SomeClass::doThing() {
// do things ...
// notify observers
for (auto* o : mObservers) {
o->thingHappened();
}
}
Run Code Online (Sandbox Code Playgroud)
如果在thingHappened观察者的实现中调用一个方法SomeClass从观察者中删除自己怎么办?有哪些最佳方法可以解决这个问题?
一种可能性是mObservers在for循环之前复制并使用它,但额外的副本可能是浪费.
另一种可能性是在循环结束后将更改委托给要运行的数组,也许在循环开始之前设置一个锁(只是一个布尔值),并且在设置此锁定时,变换向量的方法委托自己调用之后当lock设置为false时可以完成循环(可以使用lambdas向量完成...非常麻烦).
如果您可以控制签名thingHappened(),则可以更改它以返回bool指示是否应将其删除.然后,您可以删除所有返回的值true(或false;取决于您想要的语义).
对我们来说幸运的是,std::remove_if并std::partition保证在该范围内每个对象只调用一次谓词.
void SomeClass::doThing() {
// do things ...
// notify observers
auto newEnd = std::remove_if(mObservers.begin(), mObservers.end(), [](auto *o) {
return o->thingHappened();
});
// assuming mObservers is a vector
mObservers.erase(newEnd, mObservers.end());
}
Run Code Online (Sandbox Code Playgroud)
解决此问题的一种方法是更改数据结构.与std::list在除去元件的唯一的迭代器/参考/无效指针到该元件.由于列表的其余部分保持不变,我们需要做的就是在处理当前元素之前获取下一个元素的迭代器.那看起来像
for (auto it = the_list.begin(); it != the_list.end();)
{
auto next = std::next(it);
it->call_the_possibly_removing_function();
it = next;
}
Run Code Online (Sandbox Code Playgroud)