user23573
user23573

Reputation: 2569

Can I emit a signal from within a exception handler in Qt?

The Qt Documentation states:

Throwing an exception from a slot invoked by Qt's signal-slot connection mechanism is considered undefined behaviour, unless it is handled within the slot

I want the error text to be set in one of the UI objects. An elegant way to do this would be the signal/slot mechanism. Since I can have exceptions in a slot (if I handle them also in the slot) the question remains:

Is it safe to emit a signal from within the exception handler?

A related question is the connection mechanism:

Is it better (or worse) to use queued connections, or are direct connections ok?

I would like to do something like this:

class myclass : public QObject
{
    Q_OBJECT
public:
    myclass() {}

signals:
    void error_message(const std::string &);

public slots:
    void do_mogrify()
    {
         try {
              // complex function that may throw
         } catch (std::exception & e) {
             emit error_message(std::string(e.what()));
         }
    }
} 

Update:

Craig Scott points out in his answer that the arguments provided to the signal may no longer exist when the slot function is executed. So, I've changed the example to use std::string which will be copied if required (queued connection). I guess it will also work with references.

I'd like to highlight that this question is not about threads. Emitting signals from threads is covered in the Qt Documentation and here and here.

Upvotes: 2

Views: 1153

Answers (2)

Craig Scott
Craig Scott

Reputation: 10137

Emitting a signal inside a catch block is permitted. Consider carefully though the parameters you use for the signal, keeping in mind that client code gets to choose whether to connect to that signal directly or via a queued connection (i.e. you don't know which will be used at the time you emit the signal). In your example, your signal has a const char* parameter and in the catch block, you use the exception's what() function as that argument. If client code is connected to the signal via a queued connection, the const char* argument may no longer exist at the point where the slot gets called. If you want to emit signals from a catch block, consider using only parameter types which are safe to copy (e.g. std::string passed by value instead of const char*).

Queued connections will be required if you want to catch an exception in a non-GUI thread and emit the signal there, then have that signal caught in the GUI thread to display some kind of error message to the user (just one example usage scenario). Queued connections are okay as long as you are careful about the parameter types you use as mentioned above. Personally, I'd consider it wise to assume the signal emitted from your catch block could be connected via a queued connection (more robust to future changes, etc).

UPDATED:

Specifically responding to the question of whether it is better or worse to use a queued connection rather than direct, it depends on what matters to you. A direct connection is the most efficient and guarantees that your code responds to the exception immediately, but you are responsible for thread safety. A direct connection is really just going to turn a signal emission into an ordinary function call, albeit with a little bit of housekeeping along the way. A queued connection will delay the response to the exception to an arbitrary point in the future even if it is responding in the same thread (a queued response will be handled when control returns to the current thread's event loop if the object owning the slot belongs to the same thread, but there could be other signals processed first).

Your question didn't mention other connection types, but the default is Qt::AutoConnection which means the behaviour will be as for direct if the object owning the slot belongs to the same thread or queued if it belongs to a different thread, so this connection type might result in your code responding to the exception immediately or it may be delayed, which means you again need to handle thread safety yourself. A Qt::BlockingQueuedConnection would give you a guarantee that your code responds immediately but has potential negative effects on performance and requires even more care to avoid deadlock, etc.

So while your updated question indicates that you are not asking specifically about threads, the threading considerations are strongly associated with your question of which connection type is better. Ultimately, it depends on what criteria you have for better.

Upvotes: 4

AaronI
AaronI

Reputation: 862

It is safe. There is no difference between running code from an exception handler and from elsewhere. Both direct and queued connections are equally fine.

Upvotes: 3

Related Questions