Events in C++

I just implemented a small class to emulate the behavior of the C# events – I think this is called in the land of fancy-pants “The Observer Pattern”. It is not complete, nor do I intend to make it perfect – it’s as good as I need it for what I need it. The implementation is also quite small, and it’s header-only. I call it “Events, the simplest option”.

My objective is to make a clean, fast (as fast as possible) event-like interface for C++. There will be flaws, the point is to make things work first, and discuss ways to improve later. So the event-like interface is actually a simplified approach to the Observer pattern, in which you have an entity that can be signaled and subscribers will be notified.

There are two things that need to be settled here. First, the subscription. I will use for subscription a token that should be unique. Since I am pretty sure there is a boost library that does just that1)but probably there’s a boost library to create an event as well, so why even bother? I will avoid its usage, and write my own version. Because I kind of dislike boost and their approaches to life.

We have only one way to create tokens, and that is by calling TokenAllocator::CreateToken. That’s good, because we might use this strategy somewhere else. Your CreateToken can be anything, but make sure you use a lock to guard against concurrent accesses.

Now, on to the next issue. The code for the Event class.

Now this allows me to have code like this:

Now, questions. I used map because I wanted to code cleaner. The removal function for vector looks like this:

This is apropos people bugging me about how fun it is to code in C++ with the standard library. This is the definition of fugly.

It doesn’t impose a restriction that is quite nice in C# – the ability to emit only from the containing class. This can be done (we can separate the subscription aspect of it in an IEvent and expose only that), but it would complicate the code needlessly.

The use of += is doable – but -= should be implemented using the assigned token. This is, again, doable – just a bit of syntactic sugar. What we cannot nor we don’t want to do is to unsubscribe using the same function that we used for subscription. This is ugly in C# as well, I really do prefer the token version.

I don’t follow the lifetime of the subscription token. This is intentional – but this also means that your code could leak or crash easily if you don’t unsubscribe, for obvious reasons. However, the subscriptions are (obviously) automatically destroyed upon destruction of the event. This makes it easy to link the subscription lifetime to the emitter lifetime, which makes sense. But what I like is that I can subscribe and forget about it – and that’s fine.

The event is big. I mean, really big, on my machine it has 64 bytes (for the vector version) and 88 bytes for the map version. I could reduce some of this pain by having the mutex static. This works well because I don’t protect the function invocation with the mutex, I only protect the access to the internal data. This is fast enough not to be a burden for the rest of the application. But I think this version (with a mutex for each instance) is more correct.

Also, we swallow all the exceptions generated by the subscribers. In an ideal environment all your exceptions would derive from std::exception – but this is not an option all the time. That’s why I decided to do nothing about the exception – in a production environment I’d probably log something there, but we’re on my blog, not a production environment. Or something.

What was really fun here was using the variable templates. That, and the fact that you can write ugly code for your users not to have to write ugly code.

NOTES   [ + ]

1. but probably there’s a boost library to create an event as well, so why even bother?

Comments

Events in C++ — 2 Comments

Comentariul tău