QObject-Internals

From Qt Wiki
Jump to: navigation, search
IMPORTANT: The content of this page is outdated. Reason: Qt 4
If you have checked or updated this page and found the content to be suitable, please remove this notice.

How Signals and Slots Works.

See http://woboq.com/blog/how-qt-signals-slots-work.html

moc

The moc is there to generate the QMetaObject contents. It parses the headers and generate source code that contains the metaobject and the code of the signals.

Cloned Method

If you have a signal or a slot with default arguments, the signature are duplicated as if there was overload with and without those argument argument.

First is the "original" one, with the full number of argument. Then follow all the clones: they have the flag MethodFlags::MethodCloned in the QMetaObject method flags

methodIndex and signalIndex

In each QMetaObject, the slots, signals, and other invokable methods of that object have an index starting from 0. They are ordered such that the signals comes first, then the slot, then the other method.

This index is called the relativeIndex in the code, and can be obtained by QMetaObjectPrivate::indexOf{Signal,Slot}Relative. This function returns the index, but also via its baseObject argument, the QMetaObject in which that slot belogs.

The IndexOfMethod call of the QObject::qt_static_metacall function also returns that relativeIndex

Then there is the method index: it is the index returned by the public API QMetaObject::indexOf{Signal,Slot,Method} That is basically the relativeIndex + QMetaObject::methodOffset() This is the only index avaliable from the public API

The signalIndex is used from Qt 4.6 in the connectionLists. It was introduced because the connectionList only care about signals, and not the slots, and that there might be a lot of slots wasting space in that vector. It is only used internaly, and not avaliable through the public API. The main difference is that it does not contains the slots. So the signalIndex is usually less than the methodIndex for a given signal (and it only exist for signal) The second difference is that for cloned signal, we use the original instead. (Hence the call to QMetaObjectPrivate::originalClone)

connectionLists Data Structure

connectionLists is a vector of lists of connections. The index is the signalIndex, and lists are single linked list of connections represented with QObjectPrivate::Connection.

The vector contains a pointer to the first Connection for that signal, and because we want the connection to be O (1), we store also the last connection. This last connection also helps to stop before the connection that would have been added after the signal has been emitted while emitting that signal. The linked list works by following the QObjectPrivate::Connection::nextConnectionList.

The Connection's are part of another linked list: the object sender's list. This list is used to be able to remove the connections when the object is destroyed. The starts of the list is QObjectPrivate::senders. And it is a (semi-) double linked list. We can get to the next element of that list using QObjectPrivate::Connection::next. But QObjectPrivate::Connection::prev is a pointer to the Connection::next of the previous element, or the the QObjectPrivate::senders if it is the first. It is like that because we only need to iterate that list one way, but we need to quickly O (1) remove connection from that list while we disconnect (or if the sender get detroyed)

When an Object is destroyed:

  • That QObjectPrivate::senders list will be iterated when the object is destroyed, and all the Connection::receiver will be set to 0, also Connection::receiver->connectionLists->dirty will be set to true. That way removing a connection is O (1) and destroying an object is O (n), n is the number of slot of this object connected to a signal (possibly in another object)
  • each of the QObjectPrivate::connectionLists are also iterated to remove the Connection in the senders lists.

The lists are protected by the signalSlotMutex(QObject *) The connectionLists by the mutex of the sender, and the senders by the mutex of the receiver. So to modify a Connection, you need to lock the two mutex, but if you only access them, locking one mutex is enough.

History

That data structure has changed a lot in Qt4 history In Qt 4.0 it was a global, mutex protected, big list of connection, indexed with a QHash.

In Qt 4.4 it was changed to a QVector<QList<QObjectPrivate::Connection>> connectionLists and QList<QObjectPRivate::Sender> senders in order to optimize QMetaObject;;activate