Original Post
I quickly threw together a crude event system which I have included below. It allows for a quick invocation of callback handlers in a list using the notify() member function and a queuing option where the events will be delivered during the next event loop using the queue() and processQueue() methods. I am not pleased with this implementation because it was thrown together with little thought beyond the notion that it needed to support being able to invoke member function callbacks of various classes and that the signature would always be the same for all callbacks.
I was curious whether some others could offer feedback on ways I could improve this class, possibly even illustrating with code samples of more efficient alternatives. Secondly, this event system expects that all events sent through the system derive from a base class Event which is then typedef'd to a std::shared_ptr class EventPtr. What I don't like is that the senders of events are using new to allocate event objects. This is naturally bad practice when I could be allocating many event objects in short periods of time and a pool of event objects that are popped off, used, and then added back to a freelist would be far more advantageous. Unfortunately I am unclear on how best to implement such functionality since I derive various event classes from Event itself for specific event cases.
Anyone have any suggestions and thoughts?
I was curious whether some others could offer feedback on ways I could improve this class, possibly even illustrating with code samples of more efficient alternatives. Secondly, this event system expects that all events sent through the system derive from a base class Event which is then typedef'd to a std::shared_ptr class EventPtr. What I don't like is that the senders of events are using new to allocate event objects. This is naturally bad practice when I could be allocating many event objects in short periods of time and a pool of event objects that are popped off, used, and then added back to a freelist would be far more advantageous. Unfortunately I am unclear on how best to implement such functionality since I derive various event classes from Event itself for specific event cases.
Anyone have any suggestions and thoughts?
typedef boost::function<void EventPtr>)> TEventCallback;
class EventSystem
{
typedef std::vector<TEventCallback> TCallbackList;
typedef TCallbackList::iterator TCallbackListIt;
typedef std::map<EventType, TCallbackList> TCallbackMap;
typedef TCallbackMap::iterator TCallbackMapIt;
typedef std::deque<EventPtr> TEventQueue;
public:
EventSystem() { }
~EventSystem() { }
template<typename T>
void registerHandler(EventType type, T* handlerObject, void(T::* handlerCallback)(EventPtr)) {
TEventCallback cb = boost::bind(handlerCallback, handlerObject, _1);
TCallbackMapIt i = mHandlers.find(type);
if(i != mHandlers.end()) {
i->second.push_back(cb);
return;
}
mHandlers[type] = std::vector<TEventCallback>(1, cb);
}
template<typename T>
void unregisterHandler(T* handlerObject) {
TCallbackMapIt itstart = mHandlers.begin();
TCallbackMapIt itend = mHandlers.end();
for(; itstart != itend; ++itstart) {
TCallbackListIt liststart = itstart->second.begin();
TCallbackListIt listend = itstart->second.end();
while(liststart != listend) {
if(*liststart == handlerObject) {
itstart->second.erase(liststart);
break;
}
++liststart;
}
}
}
void notify(EventPtr evt) {
TCallbackMapIt i = mHandlers.find(evt->getType());
assert(i != mHandlers.end());
TCallbackListIt list = i->second.begin();
for(; list != i->second.end(); ++list)
(*list)(evt);
}
void queue(EventPtr evt) {
mQueue.push_back(evt);
}
void processQueue() {
while(!mQueue.empty()) {
EventPtr evt = mQueue.front();
mQueue.pop_front();
notify(evt);
}
}
protected:
TCallbackMap mHandlers;
TEventQueue mQueue;
};