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
On Friday, October 28, 2011, Chris Cranford wrote:
// 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?
I don't see how thats possible. Is it failing to disconnect just because the bind functor is getting copied into a boost::function due to the prototype of addListener? As was posted here recently, I don't think boost::function support visit_each to allow detection of trackable objects. One possibility is to make addListener pass its functor parameter as a template type instead of a boost::function.
participants (2)
-
Chris Cranford
-
Frank Mori Hess