The following holds: By the time the signal returns:
All directly connected slots have been invoked.
All blocking-queued connected slots have been invoked.
All of the target objects with queued-connected slots have the relevant QMetaCallEvent
posted to them.
Thus, you have the full guarantee you seek if your other code allows it, and if the connection is:
- direct,
- blocking-queued, or
- automatic with the target object in the current thread.
With those connection types, the slots are all invoked before the the signal method returns. Recall that signals are otherwise ordinary C++ methods with their implementation generated by moc.
Also recall that the automatic connection types are resolved at the time the signal is emitted. If the target object is in the current thread, a direct connection is used, otherwise a queued connection results.
Of course, all those guarantees assume that none of your slots modify the object! Don't forget that merely passing the object by const reference is not enough - after all, some objects may be able to access your object directly. The design of your code must address the guarantees that you seek.
Your guarantee necessarily can't hold if the connection is:
- queued, or
- automatic with the target object in thread other than the current thread.
Passing data by reference to directly connected slots does not copy the instances:
//main.cpp
#include <QDebug>
class Data {
int m_i;
public:
Data(const Data & o) : m_i(o.m_i) {
qDebug() << "copy constructed";
}
Data(int i = 0) : m_i(i) {
qDebug() << "constructed";
}
Data(Data && o) : m_i(o.m_i) {
qDebug() << "move constructed";
}
~Data() {
qDebug() << "destructed";
}
int i() const { return m_i; }
};
Q_DECLARE_METATYPE(Data)
QDebug operator<<(QDebug dbg, const Data & d)
{
dbg << "Data:" << d.i();
return dbg;
}
class Object : public QObject {
Q_OBJECT
public:
Q_SIGNAL void source(const Data &);
Q_SLOT void sink(const Data & d) {
qDebug() << "sinking" << d;
}
};
int main()
{
qDebug() << QT_VERSION_STR;
Object o;
o.connect(&o, SIGNAL(source(Data)), SLOT(sink(Data)));
emit o.source(Data(2));
return 0;
}
#include "main.moc"
Output:
4.8.6
constructed
sinking Data: 2
destructed
5.2.2
constructed
sinking Data: 2
destructed