Which C++ Signals/Slots Library Should I Choose

Which C++ signals/slots library should I choose?

First, try with boost::signal anyway. Don't assume it will not be fast enough until you try in your specific case that is your application

If it's not efficient enough, maybe something like FastDelegate will suit your needs? (i did'nt try it but heard it was a nice solution in some cases where boost::signal don't seem to suit).

Anyway, if in your application use the signal each frame, it may be worth to replace the signal system by something more simple, like a container that hold objects/functors that will be called each frame. Signal is more made to allow immediate "events" management than to make a loop cycle dynamic (allowing changing the functions called each frame).
(I have my own solution (UPDATE: it's very old and archaic now) that i heavily use in a game and for instance i've no problem with the performance, so maybe something similar could help).

Are signals and slots syntactic sugar or there is more to them?

Are signals and slots syntactic sugar or there is more to them? The question that I have is that, are signals and slots simply syntactic sugar for event listeners/handlers

No, the mean reason for their existence is decoupling of the emission and handling.

or what happens in the background is of different nature?

The idea is that you separate the emission from the handling of a certain "event". If you consider the direct function calls as an alternative, I would like to point that out, with them, the code responible for the emission would need to be aware of the code that actually handles the "signal". That is the two parts would be too tight too each other.

It would not be possible to dynamically add another handler for the signal without changing the code that is responsible for the signal emission. Imagine an example like this:

  • Some part of the code emits a signal "fruit arrived"

  • This code would directly call the "wash fruit" method.

What if someone would like to add a method to count the number of fruits?

  • The previous code would need to be modified to include the direct call to that method.

With the signal-slot mechanism, you would not need to touch the original code. You could just simple connect your new slot to the existing signal from an entirely different piece of code. This is called good design and freedom.

This is especially useful when you have libraries like Qt that can emit signals all around without knowing about the Qt applications in advance. It is up to the Qt applications how to handle the signals, on their own.

In addition, this pattern also makes the application more responsive and less blocking, which would be the case with direction function calls. This is because of the existence of the event loop on which the Qt signal-slot mechanism is built upon. Surely, you could use threading with direct calls, too, but it becomes a lot more work and difficult to maintain than it would be necessary in an ideal world.

So, as partially already touched, there is a QtEventLoop in the background queuing up these events for processing, although it is possible to execute "direct calls", too.

The really background internal implementation code can be found there, and in moc (meta object compiler). Moc is basically creating a function for signals which you do not define a body for, so you just declare them in the QObject subclasses when you need it.

You can read more upon the topic in here, but I think my explanation could get you going:

Qt Signals & Slots

QtDD13 - Olivier Goffart - Signals and Slots in Qt 5

How Qt Signals and Slots Work

How Qt Signals and Slots Work - Part 2 - Qt5 New Syntax

Signals and Slots in Qt5

Using the Meta-Object Compiler (moc)

what's the utility of signals and slots

In short: The main idea is decoupling in my opinion.

In longer: With direct function calls, you could not have a well-separate establishment between the common functionality and the clients of it, for instance. There would be a tight coupling unlike with signals and slots because you would need to know at the point of some condition meeting your criteria which methods exactly to call.

If you would like to gain more freedom, like with many other OOP design patterns, you need something like signals and slots. When a common component, let us call it a library, emits a signal, it does not have to be aware of the (potentially not-yet-existing) client interfaces. This makes the common component flexible enough.

It will also keep responsiveness of the application better since it is not a direct call, but processed by the Qt event loop. Arguably, you could circumvent this with custom threading mechanisms, but that would be lotta more work to make it safe enough, and you would end up doing something close this in the end of the day.

Replacing boost-signals2 with C++11 signals

The problem here is that there are two related but different technologies that are both named signals.

The signal constructs in <signal.h> and the corresponding <csignal> are signals in the POSIX sense and are related to error handling such as when the OS kills the program or a catastrophic internal error occurs.

Signals and slots such as Boost.signals2, Qt's signals/slots, etc. are a more general implementation of the observer pattern which allow one piece of code to offer a loosely coupled way for another piece of code to get a notification or callback when some event happens.

The former is really a subset of the latter since POSIX signals are mostly related to error and termination events, whereas signals and slots in general also work for less ominous events like "a network packet has arrived!" or "the user clicked a button!"

I would not recommend trying to shoehorn a general signal-slot solution into the aged (and C-style) POSIX signals API.

While there is no standard C++ signal/slot library, there is a variety of third-party libraries, as some of your links show. I wouldn't recommend rolling your own unless you have a compelling reason to reinvent the wheel. (If you must roll your own, std::function is the obvious starting point.) Boost's is a high-quality implementation, and since you're already using it, I would stick with that. (Our rule of thumb at my company is, with all things being approximately equal, "std > Boost > Qt > other", but YMMV.)

If you just want to reduce the footprint of your Boost folder, Boost supplies BCP to do just that.

Alternatives to Qt Signals and Slots for Inter-Object Communication

Qt Signal and slot mechanism is best choose in Qt programs, but if you want to know about other options, you have these:

  1. You can develop your own Observer structure that would be like Qt signal and slot but you should invent the wheel from the beginning by yourself.

    You should create an Observe class and a Subject class. In the beginning connect your Observer by passing a reference of it to Subject and as soon as the condition meet Subject will call the update function of all of the instances (emit).

    For more explanation check this link.

  2. Another option is using Boost signal2 that is also similar to Qt signal slot but from third party libraries. Usage is similar to Qt signal.

    For more explanation check this.

C++11 observer pattern (signals, slots, events, change broadcaster/listener, or whatever you want to call it)

I think that bind makes it easier to create slots (cfr. the 'preferred' syntax vs. the 'portable' syntax - that's all going away). The observer management, however, is not becoming less complex.

But as @R. Martinho Fernandes mentions: an std::vector<std::function< r(a1) > > is now easily created without the hassle for an (artificial) 'pure virtual' interface class.


Upon request: an idea on connection management - probably full of bugs, but you'll get the idea:

// note that the Func parameter is something
// like std::function< void(int,int) > or whatever, greatly simplified
// by the C++11 standard
template<typename Func>
struct signal {
typedef int Key; //
Key nextKey;
std::map<Key,Func> connections;

// note that connection management is the same in C++03 or C++11
// (until a better idea arises)
template<typename FuncLike>
Key connect( FuncLike f ) {
Key k=nextKey++;
connections[k]=f;
return k;
}

void disconnect(Key k){
connections.erase(k);
}

// note: variadic template syntax to be reviewed
// (not the main focus of this post)
template<typename Args...>
typename Func::return_value call(Args... args){
// supposing no subcription changes within call:
for(auto &connection: connections){
(*connection.second)(std::forward(...args));
}
}
};

Usage:

signal<function<void(int,int)>> xychanged;

void dump(int x, int y) { cout << x << ", " << y << endl; }

struct XY { int x, y; } xy;

auto dumpkey=xychanged.connect(dump);
auto lambdakey=xychanged.connect([&xy](int x, int y){ xy.x=x; xy.y=y; });

xychanged.call(1,2);

Qt question: How do signals and slots work?

I've actually read this Qt page about it, and it does a good job of explaining:

https://doc.qt.io/qt-5/signalsandslots.html

Qt events and signal/slots

The Qt documentation probably explains it best:

In Qt, events are objects, derived
from the abstract QEvent class, that
represent things that have happened
either within an application or as a
result of outside activity that the
application needs to know about.
Events can be received and handled by
any instance of a QObject subclass,
but they are especially relevant to
widgets. This document describes how
events are delivered and handled in a
typical application.

So events and signal/slots are two parallel mechanisms accomplishing the same things. In general, an event will be generated by an outside entity (for example, keyboard or mouse wheel) and will be delivered through the event loop in QApplication. In general, unless you set up the code, you will not be generating events. You might filter them through QObject::installEventFilter() or handle events in subclassed object by overriding the appropriate functions.

Signals and Slots are much easier to generate and receive and you can connect any two QObject subclasses. They are handled through the Metaclass (have a look at your moc_classname.cpp file for more), but most of the interclass communication that you will produce will probably use signals and slots. Signals can get delivered immediately or deferred via a queue (if you are using threads).

A signal can be generated.



Related Topics



Leave a reply



Submit