Sign in to follow this  
aeroz

List of boost::function vs boost::signals2 (for an event manager)

Recommended Posts

I have an EventManager class in my game.
For each event type it has list of boost::function. When a listener wants to register itself it calls EventManager.RegisterListener() with a callback function as argument (using boost::bind). This callback function is stored as a boost::function and is appended to the list.

Now I discovered the boost::signals(2) class. It does more or less the same as my EventManager class (but only for one event).

Would you recommend me changing to boost::signals? I would then have a list of boost:signals instead of an array of lists of boost::function.

I'm also thinking about performance, but I don't know which is faster.

Thank you very much!

[Edited by - aeroz on October 17, 2010 3:57:01 PM]

Share this post


Link to post
Share on other sites
Well, signals2 has the advantage of being designed around thread-safety, so if you're planning on using these callbacks in a multi-threaded environment, it might be worth considering. Otherwise, if it ain't broke, don't fix it; the signals library isn't particularly fast or anything.

Share this post


Link to post
Share on other sites
boost.signals2 is well engineered, maybe a little over-engineered (over-engineering in Boost!? say it ain't so!!), and whether you should use it depends on whether you want what it's selling. In addition to thread safety, signals2 gives you connection lifetime management which is well-integrated with shared_ptr, return value combining, and a few other things. If you have no need for those, there's little reason to change over.

Share this post


Link to post
Share on other sites
Thanks for the tips.

@Sneftel: I read some of your posts about event systems. Can you recommend me an internet article about the topic or even an open source game where there is a good implementation? There are maybe better solutions than having an EventManager...

Share this post


Link to post
Share on other sites
I'm posting a bit of simplified code from my event system.

EventManager:
enum EventType
{
QuitGame,
NewEntity,
DeleteEntity,
GameUpdate,
ContactAdd,
...
};

struct Event
{
EventType type;
void* data;
};

typedef boost::function<void (const Event*)> EventFunction;
typedef unsigned int FunctionId;
typedef std::map< FunctionId, EventFunction > FunctionContainer;

class EventManager
{
public:
void InvokeEvent( const Event& rEvent );

private:
FunctionId RegisterListener( const EventType eventType, EventFunction callback );
void UnregisterListener( const EventType eventType, FunctionId functionToUnregister );

FunctionContainer m_registeredCallbacks[NUM_EVENT_TYPES];
};




Listener:
in CompCollectable::XYZ:
pEventManager.RegisterListener( ContactAdd, boost::bind( &CompCollectable::Collision, this, _1 ) );

void CompCollectable::Collision( const Event* contactEvent )
{
const Contact* pContact = dynamic_cast<const Contact*>( contactEvent->data );
if( pContact == NULL )
;// handle error

// do something with the data we received
}




Generating events:

pEventManager->InvokeEvent( Event(ContactAdd, pPoint) );





I'm wondering if there is a way to have my callback functions with the parameters of the right type (not generic void*).

Then I won't need to use dynamic_cast and check if equals NULL.

I would need to change the EventManager to something like

typedef boost::function<void ()> EventFunctionVoid;
typedef boost::function<void (Entity*)> EntityEventFunction;
typedef boost::function<void (float)> GameUpdateEventFunction;
typedef boost::function<void (Contact*)> ContactAddEventFunction;
...
typedef unsigned int FunctionId;

class EventManager
{
public:
void FireQuitGameEvent();
void FireNewEntityEvent(Entity* e);
void FireDeleteEntityEvent(Entity* e);
void FireGameUpdateEvent(float dtime);
void FireContactAddEvent(Contact* c);
...

private:
FunctionId RegisterQuitGameListener( EventFunctionVoid callback );
FunctionId RegisterNewEntityListener( EntityEventFunction callback );
FunctionId RegisterDeleteEntityListener( EntityEventFunction callback );
FunctionId RegisterGameUpdateListener( GameUpdateEventFunction callback );
FunctionId RegisterContactAddListener( ContactAddEventFunction callback );
...
void UnregisterListener( FunctionId functionToUnregister );

std::map< FunctionId, EventFunctionVoid > m_registeredQuitGameCallbacks;
std::map< FunctionId, EntityEventFunction > m_registeredNewEntityCallbacks;
std::map< FunctionId, EntityEventFunction > m_registeredDeleteEntityCallbacks;
std::map< FunctionId, GameUpdateEventFunction > m_registeredGameUpdateCallbacks;
std::map< FunctionId, ContactAddEventFunction > m_registeredContactAddCallbacks;
...
};



Which doesn't seem very elegant for me.

Share this post


Link to post
Share on other sites
Quote:
Original post by aeroz
Thanks for the tips.

@Sneftel: I read some of your posts about event systems. Can you recommend me an internet article about the topic or even an open source game where there is a good implementation? There are maybe better solutions than having an EventManager...
I recall the Boost documentation having some comparisons, but really I don't know of any such article. People's choice of event system seems primarily driven by circumstances; if you're a Qt guy you use Qt's system; if you're several years ago and/or a Gtk guy you use libsigc++; if you're a Boost guy you use boost.signals or signals2; if you suffer from NIH syndrome you roll your own. Really, the one and only advantage of the system I wrote is that it was fast, at a time when boost.signals was much slower than it is now.

If you aren't going to be calling thousands of events per frame, and you don't have to work with the Qt framework, and you aren't building lightweight middleware, and you have the opportunity to choose an event system out of the blue, I would suggest boost.signals2. The boost community is a large one, it's pretty good and pretty fast code, and people will understand the code you write with it.

If you already have an event system, and you don't have a strong reason to switch, don't bother. Different systems are pretty easy to replace with each other, but DTSTTCPW and stick to what you have unless you need something else.

Share this post


Link to post
Share on other sites
Thanks for your opinion. I will stick with boost::functions for now.

Quote:
Original post by SneftelReally, the one and only advantage of the system I wrote is that it was fast, at a time when boost.signals was much slower than it is now.


This means that they did some optimizations since you wrote your code?

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this