May I have a \"dangling reference\" with the following code (in an eventual slot connected to the myQtSignal)?
class Test : public QObject
{
Q_OBJECT
si
No, you won't encounter a dangling reference. At least, not unless your slot does the sort of things that would cause problems in regular functions too.
Qt::DirectionConnection
We can generally accept that this won't be a problem for direct connections as those slots are called immediately. Your signal emission blocks until all slots have been called. Once that happens, emit myQtSignal(fooStackObject);
will return just like a regular function. In fact, myQtSignal(fooStackObject);
is a regular function! The emit keyword is entirely for your benefit--it does nothing. The signal function is just special because its code is generated by Qt's compiler: the moc.
Qt::QueuedConnection
Benjamin T has pointed out in the documentation that arguments are copied, but I think it's enlightening to explore how this works under the hood (at least in Qt 4).
If we start by compiling our project and searching around for our generated moc file, we can find something like this:
// SIGNAL 0
void Test::myQtSignal(const FooObject & _t1)
{
void *_a[] = { 0, const_cast(reinterpret_cast(&_t1)) };
QMetaObject::activate(this, &staticMetaObject, 0, _a);
}
So basically, we pass a number of things to QMetaObject::activate
: our QObject, the metaObject for our QObject's type, our signal id, and a pointer to each of the arguments our signal received.
If we investigate QMetaObject::activate, we'll find it's declared in qobject.cpp. This is something integral to how QObjects work. After browsing through some stuff that's irrelevant to this question, we find the behaviour for queued connections. This time we call QMetaObject::queued_activate with our QObject, the signal's index, an object representing the connection from signal to slot, and the arguments again.
if ((c->connectionType == Qt::AutoConnection && !receiverInSameThread)
|| (c->connectionType == Qt::QueuedConnection)) {
queued_activate(sender, signal_absolute_index, c, argv ? argv : empty_argv);
continue;
Having reached queued_activate, we've finally arrived at the real meat of the question.
First, it builds a list of connection types from the signal:
QMetaMethod m = sender->metaObject()->method(signal);
int *tmp = queuedConnectionTypes(m.parameterTypes());
The important thing in queuedConnectionTypes is that it uses QMetaType::type(const char* typeName)
to get the metatype id of the argument type from the signal's signature. This means two things:
The type must have a QMetaType id, thus it must have been registered with qRegisterMetaType.
Types are normalized. This means "const T&" and "T" map to the QMetaType id for T.
Finally, queued_activate passes the signal argument types and the given signal arguments into QMetaType::construct to copy-construct new objects with lifetimes that will last until the slot has been called in another thread. Once the event has been queued, the signal returns.
And that's basically the story.