Registering weak_ptr observer in constructor

别来无恙 提交于 2019-12-10 10:56:19

问题


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.

回答1:


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!



来源:https://stackoverflow.com/questions/53727439/registering-weak-ptr-observer-in-constructor

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!