Boost logo

Boost Users :

Subject: [Boost-users] Event system using signals2
From: Chris Cranford (crancran_at_[hidden])
Date: 2011-10-28 13:38:48


In the past, I have typically seen a lot of event systems leverage an
abstract base listener class that all classes were derived from if
they wanted to wire themselves up to a particular system, such as an
event dispatcher. This lead to giant switch statements inside the
listener's handle event method. I've used this methodology in the
past and it has worked.

But noticing that a number of articles have suggested using a
signal/slot mechanism rather than the above approach, I started trying
to implement a simple event dispatcher based on boost signals2;
however I cannot seem to make it work as I would like. See code
below:

// holds relationship of type and signal object
struct event_signal {
  int type;
  boost::signals2::signal<void(void)> sig;
};
typedef struct event_signal event_signal_t;

class EventDispatcher
{
  // other stuff left out
public:
  void addListener(int type, boost::function<void(void)> pFunction) {
    std::map<int,even_signal_t*>::iterator i = m_events.begin();
    if(i == m_events.end()) {
      event_signal_t* p = new event_signal_t;
      p->type = type;
      p->sig.connect(p);
      m_events.insert(std::make_pair(type, p));
    } else {
      m_events[type]->sig.connect(pFunction);
    }
  }
private:
  std::map<int, event_signal_t*> m_events;
};

Since signals are not copyable, I had to store a pointer to a signal.
I chose a struct in case I want to add more information later; however
I could have easily used the signal directly. The classes that I want
to wire to my event dispatcher must derive from
boost::signals2::trackable because I want their connection to be
automatically deleted upon the tracked object's destruction; so here
is my tracked object:

// base class for event system tracking
class EventTrackedObject : public boost::signal2::trackable {
public:
  EventTrackedObject() { }
  ~EventTrackedObject() { }
};

class MyObject : public EventTrackedObject {
public:
  MyObject(EventDispatcher* pDispatcher) {
    pDispatcher->addListener(E_MY_EVENT,
boost::bind(&MyObject::OnMyEvent, this));
  }
  ~MyObject() { }

  void OnMyEvent(void) { }
};

The problem with this I found is that the tracked object appears to be
getting copied at the time the boost::bind is passing itself to the
addListener() method. Is there a way to avoid this so that the
tracked object's disconnect happens as expected?

Secondly, I would prefer not to have to reference this and use the
bind call at all in my base objects and rather simply have a call that
looks like:
  pDispatcher->addListener(E_MY_EVENT, &MyObject::OnMyEvent);

Or is there a more ideal approach to my problem that I am missing?

Chris


Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net