我正在尝试重写我们的 Observer / Observable 实现,以使用 std::shared_ptr/std::weak_ptr 来消除代码中当前存在的一些令人讨厌的竞争条件。
通常,观察者在满足某些条件或构造子对象时注册自己,如下所示:
// Used to be raw 'this' now child instead derives a weak_ptr and stores it
child->addObserver(shared_from_this())
并在析构函数中注销自己,如下所示:
child->removeObserver(this); // Not shared_from_this() since in destructor
在某些情况下,这工作得很好,但是在许多情况下,观察者希望在构造函数中注册自己。由于shared_ptr尚未创建,我们无法调用shared_from_this()。
由于weak_ptr通常被推荐在C++中实现观察者模式,我想知道解决上述问题的惯用方法是什么。
一些想法:
- 让创建观察者对象的工厂注册观察者。这会泄漏观察者的抽象(为什么工厂应该知道孩子想要观察谁?)并迫使观察者公开它可能想要观察的内部对象
- 添加一个 init 方法,该方法在构造函数完成后由工厂调用,比上面更好,但是构造函数和 init 之间的语义区别是什么?应该在哪里做什么?甚至是 RAII 吗?事实上,有些语言甚至将它们的构造函数称为 init。
- 将 lambda 传递给构造函数,该构造函数采用另一个在构造后调用的 lambda
- 也许有一些模板魔法?
- 以其他方式实现观察者模式。
处理您所要求的问题的一种方法是创建一个由 a 持有的显式观察者对象实例shared_ptr
并包含在“父”中。观察者对象会将观察结果发送给父对象。
然而,由于孩子正在注册shared_ptr
to a weak_ptr
,实际上父级不需要显式地删除自己作为观察者。当孩子向观察者发送通知时,它会检查是否weak_ptr
首先是有效的。如果不再有效,它可以就地移除观察者而不是通知。
void notify_observers (Event e) const {
auto o = observers_.begin();
auto erase = [this](decltype(o) o) {
return observers_.erase(o);
};
while (o != observers_.end()) {
if (auto l = o->lock()) ++o, l->notify(e);
else o = locked_call(erase, o);
}
}
在线尝试一下! https://tio.run/##fVTRbtowFH3nK@6Y1JoVkLZHYJGmCW0PlUDbY1sh41zAqhOniUOLEPt1dm2HxF7b5QES@9zjc869iSiK0VaI80eZC1WnCDOpK1Miz5Jet5ZhpstDuKJkZSJEbfAlOWNeZzDfY27gCD/nt7cLOE17PWKshYElL91OD@iqTDqZVDtaSleFKWd@M4EK1WY1dZAGzwYw8cvM7GQ1hLsHNh6PB8fTAI6nCCl0XrXnXNk6f89a5J@O9CukuOG1MtFpV6ALLLnRJQFeER6hRFOXOXyyUqbgSfdappBrIzcHYN4@DhqfrVehawOzGdhC@9@fwFYT0MH7dgXtz/V9fu0Fee5WzXuBkROvstXmI6T6IPvvO6nSRhI1i68VekbXOVBaPDapR7u2zzN394z8MTw3Ab2usNxjWTWFBrNCcUMuzKHAnGcIi@UQLg/UMvj268fvxIF5bbQ7ldwIrhSwxZK8Dh3EQnm5rS7ORgm1SijLxHTB7JYdgFcROxfbmpfprPOWwJa5jcG0RTdBBVxh5D6rbmZce3maLhrDwN7rRRFKchaLutqt1lw80jTd2dY/sNYKoYtgpLo8x20VYab2FbpwBomxFjQkmlB/MI6rljQYzGZcYqGaBAYK1riVOQsicyAaxQrfcKIHoN924ipoP3LxTAEjMA0fojMxT1nUVHvJDTA/LFbgKLEJWNTNjR6CGiXeJ8NAqr1QkVDrKUzMiRmS1A57anKzr4qkeDIuc9f6YBJE9IEo/JMYBxPBLg3otDfop@6ouOIpEBF9H/qjEcxfCqSX9ovvohTcSOrZfd4P2f7tMHMf3GgS3iP@HBG3vP/hPJ3PfwE
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)