What are some best practices for debugging Qt signals and slots?

Debugging signals and slots can be hard, because the debugger does not jump to the slots of a signal when it is emitted. What are some best practices for debugging Qt signals and slots?

In particular

  1. How do I make sure connections are set up successfully?
  2. When should I use signals and slots, when should I avoid them?
  3. What are the most efficient debugging techniques from your experience?

What do I do if a slot is not invoked?, There was a blog post written a while back called 20 ways to debug Qt signals and slots. It addresses I think #1 and #3 of your questions. For #2, I don't think  Qt's widgets have many pre-defined slots, but it is common practice to subclass widgets and add your own slots so that you can handle the signals that you are interested in. The signals and slots mechanism is type safe: The signature of a signal must match the signature of the receiving slot.

How do I make sure connections are set up successfully?

You will see warnings in the console output from your application for each failed connection.

When should I use signals and slots, when should I avoid them?

In my opinion, it's fine to use them any time you want to maintain separation of concerns in your class design. Your class can emit a signal that may or may not be answered by another class (or classes) completely unknown to your class. This keeps your coupling down.

What are the most efficient debugging techniques from your experience?

I can't really add anything more than what is said on this blog post. 20 ways to debug Qt signals and slots

20 ways to debug Qt signals and slots, Qt automatically breaks a signal/slot connection if either the sender or the receiver is a bit cumbersome in practice: we may need a debug build of Qt and of our The good news is that all the C++ fundamental types and many Qt datatypes  Qt's widgets have many pre-defined slots, but it is common practice to subclass widgets and add your own slots so that you can handle the signals that you are interested in. The signals and slots mechanism is type safe: The signature of a signal must match the signature of the receiving slot.

Regarding #1, I'll just add another piece of information that I didn't see mentioned above or in the referenced blog post.

From the documentation on QObject::connect():

Creates a connection of the given type from the signal in the sender object to the method in the receiver object. Returns true if the connection succeeds; otherwise returns false.

I prefer asserting the return value of my connection to make sure the connection succeeded, especially because not all Qt programs will have console output. This also leads to more easily maintainable code, as it will catch changes made at a later date to either the signal or the slot, and force the programmer who made the changes to update the connections as well.

How Qt Signals and Slots Work, 20 ways to debug Qt signals and slots. Check for compiler warnings about non-existent signals and/or slots. Use break points or qDebug to check that signal and slot code is definitely reached: Check that the parameter types of the signal and slot are exactly correct and, as appropriate, that they match. In Qt we have an alternative to the callback technique. We use signals and slots. A signal is emitted when a particular event occurs. Qt's widgets have many pre-defined signals, but we can always subclass to add our own. A slot is a function that is called in reponse to a particular signal.

In addition to what have been said, here are additional tricks.

If you use QTest for your unit tests, then you can pass -vs argument to the executable and all signals will be shown in the console.

I looked at how QTest works, and it registers callbacks that is triggered when signal and slots are executed using QSignalDumper class. However, this API is not exported and might break any time. Here is how I was able to hook on all signals and slots on Linux with Qt 5.10 using GCC.

// QSignalSpyCallbackSet is defined in qt5/qtbase/src/corelib/kernel/qobject_p.h

struct QSignalSpyCallbackSet
{
    typedef void (*BeginCallback)(QObject *caller, int signal_or_method_index, void **argv);
    typedef void (*EndCallback)(QObject *caller, int signal_or_method_index);
    BeginCallback signal_begin_callback,
                    slot_begin_callback;
    EndCallback signal_end_callback,
                slot_end_callback;
};
typedef void (*register_spy_callbacks)(const QSignalSpyCallbackSet &callback_set);

static void showObject(QObject *caller, int signal_index, const QString &msg)
{
   const QMetaObject *metaObject = caller->metaObject();
   QMetaMethod member = metaObject->method(signal_index);
   qDebug() << msg << metaObject->className() << qPrintable(member.name());
}

static void onSignalBegin(QObject *caller, int signal_index, void **argv)
{
   showObject(caller, signal_index, "onSignalBegin");
}

static void onSlotBegin(QObject *caller, int signal_index, void **argv)
{
   showObject(caller, signal_index, "onSlotBegin");
}

int main(int argc, char *argv[])
{
   static QSignalSpyCallbackSet set = { onSignalBegin, onSlotBegin, 0, 0 };
   QLibrary qtcore("libQt5Core");
   register_spy_callbacks reg = (register_spy_callbacks)qtcore.resolve("_Z32qt_register_signal_spy_callbacksRK21QSignalSpyCallbackSet");

   if (reg) {
      reg(set);
   }
   ...
}

I believe that Qt should expose that API, because we could use it for so many things beyond debugging, such as monitoring the time spent in a slot, get statistics, etc.

Signals/slots best practices?, The Qt signals/slots and property system are based on the ability to introspect the Introspection means being able to list the methods and properties of an There is nothing wrong with code generators and the MOC is of a great help. In debug mode we also annotate the string with the file location for a  Debugging signals and slots can be hard, because the debugger does not jump to the slots of a signal when it is emitted. What are some best practices for debugging Qt signals and slots? In particular

Debugging singal-slot connections, Hey there, I've been looking at the maintainability of other people's code when they've written stuff that uses signals and slots, and have been  Qt's widgets have many pre-defined slots, but it is common practice to subclass widgets and add your own slots so that you can handle the signals that you are interested in. The signals and slots mechanism is type safe: The signature of a signal must match the signature of the receiving slot.

Signals & Slots, When working on a large Qt software project the amount of signal-slot connections can really go through the roof. During run-time I often want  All slots connected to the emitted signal will be executed. You shouldn't think of Signals as events, because as you can read in the Qt documentation: When a signal is emitted, the slots connected to it are usually executed immediately, just like a normal function call.

Queued Custom Type Example, Qt's widgets have many pre-defined slots, but it is common practice to subclass widgets and add your own slots so that you can handle the signals that you are  The syntax used for Qt's signals and slots has proved very successful in practice. The syntax is intuitive, simple to use and easy to read. People learning Qt find the syntax helps them understand and utilize the signals and slots concept -- despite its highly abstract and generic nature.

Comments
  • The link you provided is rather underwhelming in terms of actual debugging techniques. The gist is basically: "Avoid writing bugs, and here are 20 things that can go wrong". No mention of tools or techniques to actually debug issues. When you get a crash dump, you are confronted with an insanely deep callstack, lots of qt_static_metacall invocations, no easy way to decipher the emitted signal, and simply no way of knowing, where any particular signal-slot-connection was set up.