Is it possible to send signals to a slot without connecting them?
There is a class that has a SLOT which shows some logs.
For now we don't have any information how many classes will be use to send signals to this log slot, and we won't be able to address their objects to each other, but every objects might send logging request.
You can call an object's (public) slot just like you call a normal member function. A connection is not necessary.
Besides, you don't need to know in advance who will connect to a given slot. The connection can happen outside your class. (For public slots at least.)
Yes you may, in a few ways.
You may call the slot like any other C++ function (if it is public). Slots are still C++ functions. The downside is that the caller needs to know the receiver's interface at compile time.
logger.log("The frobnitz could not be quuxed");
You may invoke the slot via QMetaObject::invokeMethod. With this method, the caller doesn't need any compile-time info about the recipient other than the fact that it is a QObject*.
if (!QMetaObject::invokeMethod(logger, "log", Q_ARG(QString, "The frobnitz could not be quuxed"))) {
qWarning("Internal error: logging failed (did someone change the logger API?)");
}
I think there is no such possibility. But maybe you can just make log() method static, so you will be able to call log() method without referencing logger object?
Related
I am currently creating my own GUI-Library based on SFML.
At the moment i am working on a Button. So when creating a button you also have to specify a callback which is a function, executed on the button click.
Now, I'm answering me what the disadvantages are of using just a pointer to a function as a button-callback, because I don't know any popular GUI-Library doing it so simply, too.
If the callback function is a long process, I would execute it in a new thread, but i'm not sure about that in the moment.
So, what would be reasons, not to use such simple solution and especially, what would be a better way?
It's a tricky problem!
Function pointers are simple to implement on the sender side, but they are difficult to use on the receiver side because they they don't have any context.
One issue is that a function pointer cannot point to a member function. That's why you often see (C-style) frameworks pass an arbitrary void *userData to their callbacks, so you can cast your this pointer and retrieve it in that way. This still needs you to write a static wrapper function to cast the pointer back and call the member function.
A more modern solution would be to use std::function. This can contain a regular function pointer, a member function pointer, but also a lambda or a functor.
However, when you add context like this (or in some other way), you quickly run into difficulties with lifetimes. When the receiving class is destroyed before the sender, what is supposed to happen? If you don't do anything, this situation will result in undefined behaviour. A solution is to track on the receiver side to which events the receiver is subscribed, and unbind them before the receiver is destroyed. And this needs to be done in both directions: when the sender is destroyed, it also needs to notify the receiver that it should forget about the sender, otherwise the receiver would later try to unbind an event that no longer exists.
And I haven't even begun to think about multithreading yet...
There are libraries that solve these problems in various ways, for example eventpp (just found through a web search, this is not an endorsement).
Another one to mention would be the Qt toolkit, which went so far as to write their own small signals and slots extension to the C++ language (implemented as a code generator and a pile of macros) to solve this problem in a very ergonomical way.
what the disadvantages are of using just a pointer to a function as a button-callback
Passing some context argument to that function would come handy.
I mean, the UI may have a lot of buttons performing the same action on various objects. Think maybe of "send message" button next to each nick in a friend list.
So you may want your buttom to pass some context arguments to the call.
But since we're talking C++, this'd better be abstracted as
struct IButtonAction
{
virtual void OnAttached() = 0;
virtual void OnDetached() = 0;
virtual void OnClick() = 0;
};
And let the client code implement this interface storing whichever Arg1, Arg2, etc in each instance object.
The button class would call OnAttached/OnDetached when it begins/ends using the pointer to an instance of this callback interface. These calls must be paired. Client implementation of these methods may perform lifetime management and synchronization with OnClick, if required.
OnClick method performs the action.
I don't think the button should bother with threads. It's the responsibility of the client code to decide whether to spawn a thread for a lengthy action.
I'm learning Qt and I'm having lots of fun with the signals-slotpattern. The question that I have is that, are signals and slots simply syntactic sugar for event listeners and handlers or what happens in the background is of different nature? If the later, what is the fundamental difference?
This is not just syntactic sugar. There is a real work in the background of Qt signals/slots. This work is done by the MOC (Meta-Object Compiler). This is the reason there is a process on all of your C++ header files that contains class with Q_OBJECT macros.
The "hard part" of signals/slots is when you are in a multithreading context. Indeed, the Qt::ConnectionType argument of connect() function, which is Direct (e.g. direct call of the function) in a single-threaded environment, is Queued in a if sender and emitter aren't in the same thread. In this case, the signal must be handled by the Qt event loop.
For more details: http://qt-project.org/doc/qt-4.8/signalsandslots.html
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)
The signals and slots are a way to decouple the method call from the called method. They are not syntactic sugar at all since they add no new syntax to the C++ language. A signal emission is a method call. A slot is a plain old instance method. The code that links the two is plain old C++. Nothing new here - no sugar of any kind.
Most of what you call "the syntactic sugar" is akin to comments - those are empty defines (Q_SLOT, Q_SIGNAL, signals, slots) used to mark the methods for processing by the meta object compiler (moc). Moc generates introspection information and signal implementations based on normal C++ syntax of the declarations (with some limitations).
I claim that this is not syntactic sugar since moc understands regular C++ and generates introspection data based not on any syntactic sugar, but on usual instance method declarations. The "sugar" is there to avoid the premature pessimization of having moc generate metadata for everything in a class's declaration. It also lets moc ignore the method definitions - otherwise it'd need to parse them, and assume that methods without definitions are signals.
The emit macro is only for human consumption and is merely an indication that a method call is really a signal emission. It's not used by moc. It's defined to be empty.
The Q_OBJECT and Q_GADGET macros declare some class members used to access the metadata. They are, arguably, the only piece of real "sugar" since it saves you from having to type out a few lines of declarations.
There's quite a bit of code potentially involved in making it work.
A signal:
is an instance method whose implementation is generated by moc,
has full introspection information about its name and arguments. This is available as an instance of QMetaMethod.
A slot:
is an instance method whose implementation you provide,
similarly has full introspection information.
The metainformation is available at runtime and can be enumerated and used by code that has no prior knowledge of the signal's nor slot's signature.
When you emit a signal, you simply call the method generated by moc. This method invokes Qt library code that acquires relevant mutexes, iterates the list of attached slots, and executes the calls, acquiring additional mutexes as needed along the way. Doing this properly requires care, since the sender and receiver objects can reside in different threads. One has to avoid delivery of slot calls to non-existent objects. Oh, you don't want deadlocks either. This requires some forethought.
Since both signals and slots are just methods, you can certainly connect signals to other signals - the underlying mechanism doesn't care what gets called, it's just an invokable method. Non-invokable methods are those without metadata.
A slot gets invoked when the relevant signal is emitted. A signal emission is just a method call to the generated body of the signal. This is different from event-listener pattern, since the slot invocation can be either immediate (so-called direct connection) or deferred to the event loop (so-called queued connection). A queued slot call is implemented by copying the arguments and bundling them in a QMetaCallEvent. This event is "converted" back into a method call by QObject::event. This happens when the event loop delivers the event to the target object.
The metadata contains more than just signal and slot signatures. It also allows you to default- and copy-construct signal/slot parameter types - this is necessary to implement the queued calls. It also contains key-value pairs for enumerations - that's what makes Qt rather easy to script. All enum values passed to Qt methods can be looked up by name, at runtime!
I have a singleton class for logging purpose in my Qt project. In each class except the singleton one, there is a pointer point to the singleton object and a signal connected to an writing slot in the singleton object. Whichever class wants to write log info just emit that signal. The signals are queued so it's thread-safe.
Please critique this approach from OOP point of view, thanks.
=============================================================================================
Edit 1:
Thank you all your applies, listening to opposite opinions is always a big learning.
Let me explain more about my approach and what I did in my code so far:
Exactly as MikeMB pointer, the singleton class has a static function like get_instance() that returns a reference to that singleton. I stored it in a local pointer in each class's constructor, so it will be destroyed after the constructor returns. It is convenient for checking if I got a null pointer and makes the code more readable. I don't like something as this:
if(mySingletonClass::gerInstance() == NULL) { ... }
connect(gerInstance(), SIGNAL(write(QString)), this, SLOT(write(QString)));
because it is more expensive than this:
QPointer<mySingletonClass> singletonInstance = mySingletonClass::getInstance();
if(singletonInstance.isNull) { ... }
connect(singletonInstance, SIGNAL(write(QString)), this, SLOT(write(QString)));
Calling a function twice is more expensive than creating a local variable from ASM's point of view because of push, pop and return address calculation.
Here is my singleton class:
class CSuperLog : public QObject
{
Q_OBJECT
public:
// This static function creates its instance on the first call
// and returns it's own instance just created
// It only returns its own instance on the later calls
static QPointer<CSuperLog> getInstance(void); //
~CSuperLog();
public slots:
void writingLog(QString aline);
private:
static bool ready;
static bool instanceFlag;
static bool initSuccess;
static QPointer<CSuperLog> ptrInstance;
QTextStream * stream;
QFile * oFile;
QString logFile;
explicit CSuperLog(QObject *parent = 0);
};
I call getInstance() at the beginning of main() so make sure it is read immediately for each other class whenever they need to log important information.
MikeMB:
Your approach is making a middle man sitting in between, it makes the path of the logging info much longer because the signals in Qt are always queued except you make direct connection. The reason why I can't make direct connection here is it make the class non-thread-safe since I use threads in each other classes. Yes, someone will say you can use Mutex, but mutex also creates a queue when more than one thread competing on the same resource. Why don't you use the existing mechanism in Qt instead of making your own?
Thank you all of your posts!
=========================================================
Edit 2:
To Marcel Blanck:
I like your approach as well because you considered resource competition.
Almost in every class, I need signals and slots, so I need QObject, and this is why I choose Qt.
There should be only one instance for one static object, if I didn't get it wrong.
Using semaphores is same as using signals/slots in Qt, both generates message queue.
There always be pros and cons regarding the software design pattern and the application performance. Adding more layers in between makes your code more flexible, but decreases the performance significantly on those lower-configured hardware, making your application depending one most powerful hardware, and that's why most of modern OSes are written in pure C and ASM. How to balance them is really a big challenge.
Could you please explain a little bit more about your static Logger factory approach? Thanks.
I do not like singletons so much because it is always unclean to use them. I have even read job descriptions that say "Knowledge of design patterns while knowing that Singleton isn't one to use". Singleton leads to dependecy hell and if you ever want to change to a completely different logging approach (mabe for testing or production), while not destroying the old one you, need to change a lot.
Another problem with the approch is the usage of signals. Yes get thread savety for free, and do not interrupt the code execution so much but...
Every object you log from needs to be a QObject
If you hunt crashes your last logs will not be printed because the logger had no time to do it before the program crashed.
I would print directly. Maybe you can have a static Logger factory that returns a logger so you can have one logger object in every thread (memory impact will still be very small). Or you have one that is threadsave using semaphores and has a static interface. In both cases the logger should be used via an interface to be more flexible later.
Also make sure that your approach prints directly. Even printf writes to a buffer before being printed and you need to flush it every time or you might never find crashes under bad circumstances, if hunting for them.
Just my 2 cents.
I would consider separating the fact that a logger should be unique, and how the other classes get an instance of the logger class.
Creating and obtaining an instance of the logger could be handled in some sort of factory that internally encapsulates its construction and makes only one instance if need be.
Then, the way that the other classes get an instance of the logger could be handled via Dependency injection or by a static method defined on the aforementioned factory. Using dependency injection, you create the logger first, then inject it into the other classes once created.
A singleton usually has a static function like get_instance() that returns a reference to that singleton, so you don't need to store a pointer to the singleton in every object.
Furthermore it makes no sense, to let each object connect its log signal to the logging slot of the logging object itself, because that makes each and every class in your project dependent on your logging class. Instead, let a class just emit the signal with the log information and establish the connection somewhere central on a higher level (e.g. when setting up your system in the main function). So your other classes don't have to know who is listening (if at all) and you can easily modify or replace your logging class and mechanism.
Btw.: There are already pretty advanced logging libraries out there, so you should find out if you can use one of them or at least, how they are used and adapt that concept to your needs.
==========================
EDIT 1 (response to EDIT 1 of QtFan):
Sorry, apparently I miss understood you because I thought the pointer would be a class member and not only a local variable in the constructor which is of course fine.
Let me also clarify what I meant by making the connection on a higher level:
This was solely aimed at where you make the connection - i.e. where you put the line
connect(gerInstance(), SIGNAL(write(QString)), this, SLOT(write(QString)));
I was suggesting to put this somewhere outside the class e.g. into the main function. So the pseudo code would look something like this:
void main() {
create Thread1
create Thread2
create Thread3
create Logger
connect Thread1 signal to Logger slot
connect Thread2 signal to Logger slot
connect Thread3 signal to Logger slot
run Thread1
run Thread2
run Thread3
}
This has the advantage that your classes don't have to be aware of the kind of logger you are using and whether there is only one or multiple or no one at all. I think the whole idea about signals and slots is that the emitting object doesn't need to know where its signals are processed and the receiving class doesn't have to know where the signals are coming from.
Of course, this is only feasible, if you don't create your objects / threads dynamically during the program's run time. It also doesn't work, if you want to log during the creation of your objects.
In C++, public means those members that are accessible from anywhere where the object is visible, private means that members are accessible only from within other members of the same class or from their friends.
But in Qt, the difference in private slots and public slots seem not to exist. I have begun writing Qt in recent days, and I used private slots all the time.
Someone told me I should use public slots instead. So now I am puzzled. I can not find reference info in the Qt`s docs.
What's the actual difference between the two types?
From Qt Documentation:
Since slots are normal member functions, they follow the normal C++ rules when called directly. However, as slots, they can be invoked by any component, regardless of its access level, via a signal-slot connection. This means that a signal emitted from an instance of an arbitrary class can cause a private slot to be invoked in an instance of an unrelated class.
What this means: From another class, you can't call a private slot as a function, but if you emit a signal connected to that private slot, you can invoke it.
The private/public access is “checked” by the compiler at compile time, but the signal-slot connection is performed at run-time and slots are invoked by some QMetaObject mechanisms (something like for example invokeMethod).
So the difference is this: private slots are private if called as regular member functions but always "public" for signals to invoke, a good reason is because slots conceptually are public interface, since their main purpose is inter-object communication
Another example about some related “weird” stuff is the call of private virtual functions if they are public in the static type of the pointer that is used to call the method.
#user2448027 answer is correct, but there is a missing point in Qt's design pattern: different applications of private slots vs public slots.
By making slot private you force users of the object to use connect function to call the slot, rather than member access operators(. or ->).
Imagine you have a slow or blocking code in one of the slots of your class. You expect users of the class to move the created object to another thread, so the owner of this object (GUI or some object's related to GUI) would not freeze or block by calling this slot. Here is the point: if the slot is called directly by . or -> operators, it will block. Because the current thread of caller method uses the slot, it can only happen if you use public slot. The solution is to make the slot private, so the user could only call it with connect, but not member access operators(. or ->).
Conclusion:
If you have blocking slots, make them private.
If the slots are used as simple settings of object property, make them public.
If you need some methods with return values or inconstant reference arguments, do not even make them slots (it is nonsense), only public is enough.
I've been bashing my head for the last two nights trying to figure this out with no positive results. There is the thing, in boost signals, every time I want to connect, say, a member function of one class to another's class signal, I have to save the resulting connection in a variable if I want to disconnect later. If later on, I want to connect the same member function to some other class signal (the member function is still connected with the previous class signal) I have to save this new connection in order to manage it too. My question is, is there any way to avoid this?
You shouldn't need to keep connection instances around, you should be able to disconnect from a signal by passing the original callable to signal::disconnect, as described in the Boost.Signals tutorial. With member functions the problem is rather the fact that you cannot pass them directly to signal, you either wrap them in custom function objects, which would then be available as arguments to signal::disconnect or you use Boost.Bind, which by itself wouldn't be very useful as you cannot conveniently declare its return type. However that problem can be solved using Boost.Bind together with Boost.Function.
I hope I answered your question.
Scoped Connections
Alternatively you could assign the returned connection to a variable of type signal::scoped_connection. It's a type of connection which automatically disconnects on destruction or reassignment. This effectively limits a signal-slot connection lifetime to a particular scope.
For example when you reassign myConnection, the previous connection is automatically disconnected:
scoped_connection myConnection = someObject.Signal.connect(MyHandler);
myConnection = totallyDifferentObject.Signal.connect(MyHandler);
Automatic Connection Management
In our project, we usually declare member variables as scoped connections. So their scope matches the live time of the particular object instance the belong to. This is a convenient way to automatically disconnect any signals an object instance is connected to when it is being destructed. Without scoped connections you have to manually disconnect yourself in the destructor. If you neglect to disconnect instances when they're destroyed, you'll end up invoking invalid signal handlers which will crash your programs.