HiveBrain v1.2.0
Get Started
← Back to all entries
patterncppMinor

C++11 event system

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
systemeventstackoverflow

Problem

I've implemented an events system in C++11. I've now got it pretty much as good as I can get it. It feels like I have found an optimal design pattern, and I'm using sensible variable names to illustrate what is going on.

Still not sure what the best words are: e.g. Invoker, Dispatcher, or Notifier? Event.fire() or .publish() or .trigger()? Reciever, Listener, or Subscriber? etc...

As is a fairly involved machinery, I've taken trouble to document. I would be very grateful if anyone can offer more concise or improved documentation, as I find that my ability to document something starts to decrease once I get close to fully understanding it, as I forget the sequence of key observations necessary to grok the structure. What would you modify if you were to assimilate this into your code base?

Coliru

```
// C++11 Event System
// π 06.03.2016
// 5th revision

#include
#include
#include
#include
#include

using namespace std;
/*
Usage:

Event event;

class Reciever : EventManager {
void handler(int k) {...}

reciever.connect(event, &Reciever::handler);

event.fire(42);

Internals:

Terminology
An Invoker is a machine for invoking a particular member function of a particular instance of a particular object type.
e.g.
class T { void f(int i) {cout needs to hold a list of Invokers (as InvokerBase*), such that when the event fires,
every connected invoker does its invoke().
EventManager needs to hold a list of Event (as EventBase) so that when a listener is destroyed,
all events connecting into it are told to remove all relevant invokers.

We have to use a InvokerBase base class as invokers of potentially of different types
We have to use an EventBase base class as events are potentially of different types

Details:
Event contains a list of Invoker-s, each invoker holding a T t and a void(T::f)(Args…).
Event also contains a void fire(Args… args), which calls t->f(…

Solution

Design OVerview

I think your naming convention is slightly different from normal:

// I would have called this the EventSource.
// The object that events are coming from.
// Because this is the object the fires an event.
Event event;

// I would have called this the EventListener
// The object that listen for and react to event actions.
// But note: They are not necessarily the exclusive receiver of an event
//           Which "Receiver" implies.
class Reciever : EventManager {
    void handler(int k) {...}

// Here "42" is the Event that is happening.
event.fire(42);


I also think you interface for registering is convoluted:

reciever.connect(event, &Reciever::handler);


I suppose you can do it this way. But I would have registered the receiver with the class that is generating the events (because there could be more than one receiver of events).

event.connect(reciever); // Should not even need to tell them what
                         // function to call that is implied by the
                         // type of event.


Code Review
Never do this

using namespace std;


Especially since this is a header file that will be included by other people's code.

If I include this into my code this change can break how my code works. Most projects will ban the use of your project if you put this in the header file for this reason. So don't do it.

Even putting this line in a source file is bad idea. It can silently cause breaks in your code. This is a good article about the issue.Why is “using namespace std;” considered bad practice?
Std::function

Your class InvokerBase and Invoker seem to be reinventing the std::function class. The use of lambdas and std::function have basically eliminated the need for these types of class. Please use the classes that have been provided by the standard.

Code Snippets

// I would have called this the EventSource.
// The object that events are coming from.
// Because this is the object the fires an event.
Event<int> event;

// I would have called this the EventListener
// The object that listen for and react to event actions.
// But note: They are not necessarily the exclusive receiver of an event
//           Which "Receiver" implies.
class Reciever : EventManager<Reciever> {
    void handler(int k) {...}

// Here "42" is the Event that is happening.
event.fire(42);
reciever.connect(event, &Reciever::handler);
event.connect(reciever); // Should not even need to tell them what
                         // function to call that is implied by the
                         // type of event.
using namespace std;

Context

StackExchange Code Review Q#122440, answer score: 3

Revisions (0)

No revisions yet.