在构造函数中注册weak_ptr观察者 [英] Registering weak_ptr observer in constructor

查看:69
本文介绍了在构造函数中注册weak_ptr观察者的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试重写我们的Observer/Observable实现,以使用std :: shared_ptr/std :: weak_ptr摆脱代码中当前存在的某些讨厌的竞争条件.

通常,观察者在满足某些条件时或在构造子对象时进行注册,例如:

 //以前是原始的'this',现在,子级派生weak_ptr并将其存储子> addObserver(shared_from_this()) 

然后像下面这样在析构函数中注销自己:

  child-> removeObserver(this);//自从析构函数以来,不是shared_from_this() 

在某些情况下,它可以正常工作,但是在许多情况下,观察者希望在构造函数中进行注册.由于尚未创建shared_ptr,因此我们无法调用shared_from_this().

由于通常建议使用weak_ptr来在C ++中实现观察者模式,所以我想知道解决上述问题的惯用方式是什么.

一些想法:

  • 让创建观察者对象的工厂注册观察者.这会泄漏观察者的抽象(工厂为什么要知道孩子想观察谁?),并迫使观察者暴露可能要观察的内部物体
  • 添加一个初始化方法,该方法在构造函数完成后由工厂调用,这比上面的方法更好,但是构造函数和init之间的语义区别到底是什么?在哪里应该做什么?甚至是RAII吗?确实,某些语言甚至将其构造函数称为init.
  • 将lambda传递给构造函数,该构造函数将使用另一个在构造后被调用的lambda
  • 也许有些模板魔术?
  • 以其他方式实现观察者模式.

解决方案

一种解决问题的方法是创建一个由 shared_ptr 持有并包含的显式观察者对象实例.在父母"中.观察者对象会将观察分派给父对象.

但是,由于子级正在将 shared_ptr 注册到 weak_ptr ,因此实际上父级不需要显式地将其自身删除.当孩子向观察者发出通知时,它会先检查 weak_ptr 是否有效.如果它不再有效,则可以在原位删除观察者,而不必进行通知.

  void notify_observers(Event e)const {自动o = Observers_.begin();自动清除= [this](decltype(o)o){返回观察者_.erase(o);};while(o!= observers_.end()){if(auto l = o-> lock())++ o,l-> notify(e);否则o = locked_call(erase,o);}} 

I'm trying to rewrite our Observer / Observable implementation to use std::shared_ptr/std::weak_ptr to get rid of some nasty race conditions currently present in the code.

Typically, the observers registers themselves when some condition is met or when they are constructing child objects like so:

// Used to be raw 'this' now child instead derives a weak_ptr and stores it
child->addObserver(shared_from_this()) 

And unregisters themselves in destructor like so:

child->removeObserver(this); // Not shared_from_this() since in destructor

In some situations this works fine, however in many instances the observer wants to register itself when in constructor. Since the shared_ptr hasn't been created yet we cannot call shared_from_this().

Since the weak_ptr is commonly recomended to implement the observer pattern in C++ I'm wondering what the idiomatic way to solve the above problem is.

Some thoughts:

  • Let factory that creates the observer object register the observer. This leaks abstractions from the observer (why should the factory know who the child wants to observe?) and forces observer to expose internal objects that it may want to observe
  • Add an init method that gets called by factory after constructor is complete, better than above but what is the semantic difference between a constructor and init anyway? What should be done where? Is it even RAII? Indeed, some languages even call their constructors init.
  • Pass a lambda to constructor that takes another lambda that gets called after construction
  • Some template magic maybe?
  • Implement the observer pattern in some other way.

解决方案

One way to deal with the problem as you have asked it is to create an explicit observer object instance held by a shared_ptr and contained in the "parent". The observer object would dispatch observations to the parent.

However, since the child is registering a shared_ptr to a weak_ptr, there is actually no need for the parent to remove itself as an observer explicitly. When the child is sending out notifications to observers, it checks if the weak_ptr is valid first. If it is no longer valid, it can remove the observer in situ instead of notifying.

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);
    }
}

Try it online!

这篇关于在构造函数中注册weak_ptr观察者的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆