Boost logo

Boost Users :

From: Lang Stefan (SLang_at_[hidden])
Date: 2008-06-26 04:32:40

Have you seen my previous post on this matter? I suggested extracting the services that your children need to refer to a superclass. You can solve your observer pattern in the same way, and much more elegantly besides. Here's an example:

class Notification; // forward declaration - add any details your 'children' want to talk about
Template <class Observable>
class Observer {
  void register(const Observable* observable); // might call notify() below
  void unregister(const Observable* observable); // might call notify() below
  virtual void notify(const Notification* notification) = 0;
  void stopNotification(); // call to prevent forwarding notifications
// ...

class MyChild; // forward decl.
// MyParent definition.
// note that for readability purposes I added the method definitions inline,
// although they need to be defined after the MyChild definition. Move these
// to the implementation file if needed!
class MyParent : public Observer<MyChild> {
  MyParent() : m_child(new MyChild(this)) {}
  ~MyParent() { stopNotification(); delete m_child; }
  virtual void notify(const Notification* notification); // react to notifications here!
// ...
  MyChild* m_child;
class MyChild {
  MyChild(Observer* myParent) : m_parent(myParent) { m_parent.register(this); }
  ~MyChild() { m_parent.unregister(this); }
  Observer* m_parent;

The Observer base object of the parent will still be valid at least to the point where the MyParent destructor code ends. This means the MyChild object is free to call Observer::unregister(). MyParent's call to stopNotification() makes sure Observer::unregister() does not call MyParent::notify() which may not be valid at this point.

Unless I'm missing something important this should work perfectly: Moreover, your Observer pattern implementation is independent from your actual Parent or Child classes and can be reused. Basically, whenever you have a structure where a 'child' needs to acces a specific service from a 'parent', consider whether this service can be extracted into an independent super class or interface like I did above.

Hope this helps,

-----Ursprüngliche Nachricht-----
Dealing out a weak_ptr to a child, convert it to a shared_ptr when needed does not prevent the parent getting deleted in a next sequence of calls, leading to have a pointer to a child, without an exisitng parent. Other posts where about the need for calling the parent during destruction. Well there is one major
case: if a parent is the observer of its child, the destructor of the child is the ideal candidate for unregistering. But in above case it leads to crashes.
Although in this case the parent gets destroyed (in which the unregistering at the parent may be superfluous) there may be other observers for the child.

All in all if I think about it, it can be solved (through a global register for instance), but not with above described proposal, which was attractive due to local character of the solution (child know only parents, maybe one class more). Then again it seems that c# and a gc wouldn't help in this case either.
They break a cyclcic dependency, but it is forbidden to call object references in finalizers. Then again to get at that stage all observing objcts to the child had already give up their referneces, e.g soemthing like (in c++):

   std::for_each(m_vChilds.begin(), m_vChilds.begin(),
                 boost::bind(&Parent::Notify, this, _1, eDelete);

   //type std::vector< boost::shared_ptr<Child> >


I know this sounds a little bit over the top, but we develop a pretty large application in our company, where you can not track all pointer of lifetime of object. Ideally a framework would solve lifetiem problems. Boost smart_ptr's help (and do a great job), but not completely.


Boost-users mailing list

End of Boost-users Digest, Vol 1672, Issue 5

Boost-users list run by williamkempf at, kalb at, bjorn.karlsson at, gregod at, wekempf at