How to catch exceptions in Qt?
Solution 1
where am I supposed to catch it?
This is exactly why Qt does not support throwing exceptions across signal/slot connections. If you try it, you'll see this message:
Qt has caught an exception thrown from an event handler. Throwing exceptions from an event handler is not supported in Qt. You must reimplement QApplication::notify() and catch all exceptions there.
As it mentions, it is possible to subclass QApplication and catch your exception there, but that will be a very annoying way of handling things.
If possible, I would recommend rewriting count such that it does not throw.
What if you can't rewrite count()?
For example, what if count() is part of a function in a 3rd-party library that you're using?
No slot in any official Qt library throws, so if you're using a third-party library with a slot that throws, it's probably a sign that it's not a good library. If you want to use it anyway, I recommend that rather than catching it in QApplication::notify
, that you instead create an adapter.
What does that mean? First create an object that takes in your sketchy third-party object in the constructor. In it, write a slot that wraps a call to the throwing slot with a try/catch block. Now instead of connecting to the sketchy third-party object's slot, connect to your newly create object's slot.
Doing the exception catching this way keeps related code together, and prevents QApplication::notify
from filling up with a bunch of unrelated try/catch blocks if you encounter more than one of these problematic functions.
For example:
class BadCounter {
Q_OBJECT
public slots:
void count() { throw CounterError("unable to count"); }
};
class CounterAdaptor {
Q_OBJECT
BadCounter* counter_;
public:
CounterAdaptor(BadCounter* counter) {
counter_ = counter;
}
public slots:
void count() {
try {
counter_->count();
} catch (const CounterError& e) {
std::cerr << e.what() << std::endl;
}
}
};
int main() {
BadCounter engine;
CounterAdaptor adaptor(&engine);
QThread* thread = new QThread();
connect(thread,SIGNAL(started()),&adaptor,SLOT(count()));
thread.start();
... // etc...
delete thread;
}
What if you want to handle something that could be thrown from anywhere?
The obvious example of this sort of global concern is an unexpected exception. Mistakes can happen anywhere. It would be desirable to log as many details about the event as possible so the cause could be identified and corrected. In this case, you would want to reimplement QApplication::notify
in your own subclass as shown in jichi's answer. Using a global handler for global concerns is quite reasonable.
Solution 2
If someone needs an example code to override QApplication::notify, I got one from here (in Japanese): http://www.02.246.ne.jp/~torutk/cxx/qt/QtMemo.html
#include "MyApplication.h"
#include <exception>
MyApplication::MyApplication(int& argc, char** argv) :
QApplication(argc, argv) {}
bool MyApplication::notify(QObject* receiver, QEvent* event) {
bool done = true;
try {
done = QApplication::notify(receiver, event);
} catch (const std::exception& ex) {
// ログや何らかの回復処理
} catch (...) {
// ログや何らかの回復処理
}
return done;
}
Related videos on Youtube
smallB
Updated on July 09, 2022Comments
-
smallB almost 2 years
try { // `count()` throws exception connect(thread, SIGNAL(started()), engine, SLOT(count())); } catch(const X& e) {}
As of Qt-5, I get following error:
Qt has caught an exception thrown from an event handler. Throwing exceptions from an event handler is not supported in Qt. You must not let any exception whatsoever propagate through Qt code. If that is not possible, in Qt 5 you must at least re-implement
QCoreApplication::notify()
and catch all exceptions there.If I can't catch the exceptions in conventional way as shown above, then where are we supposed to catch those?
-
Adrian about 12 yearsMaybe you should put the try-catch block in the count() function...
-
Adrian about 12 yearsThen your solution provided in the question is good
-
-
smallB about 12 years#vBx you don't use any signals/slots connection, am I missing something?
-
Alok Save about 12 years@smallB: Signals and slots are QT specific constructs, what vBx gives you here is the standard C++ solution.
-
smallB about 12 years@Als I see that but my question is qt specific. I thought the notion of signal slot would be a good give away. Also if you would note I don't ask how to use try catch block.
-
Nicol Bolas about 12 years@smallB: Your question is in no way Qt specific. Qt is C++; it may have special macros and it's own special little pre-compiler and build projects, but it's still C++. The fact that you happen to use signals changes nothing about exception handling.
-
alexisdm about 12 years@NicolBolas the question is very Qt specific:
count()
will be called asynchronously, so knowning where the exception is handled is not as easy as it seems. -
Mark Ransom about 12 years@alexisdm, can you explain that a little? Generally parameters to a function are fully evaluated before the function is called. How does the SLOT macro make it asynchronous?
-
smallB about 12 years@vBx son where did I cry? I've just tried to explained to you that you didn't understand what I'm asking about.
-
smallB about 12 years@NicolBolas 9 out of ten persons (who know C++ and Qt), if you tell them words signal/slot will immediately associate this with typical Qt pattern. One will not. I feel sorry for you.
-
smallB about 12 yearsyes, I believe I'll have to rewrite this and don't throw. Thanks.
-
alexisdm about 12 yearsThis is a string, not a function call:
SLOT(count()) == "1slot()"
(or maybe "2slot()" I'm not sure). -
smallB about 12 years@NicolBolas also there are persons who by reading tags (c++, qt) would immediately associate this question as a qt specific. As I've said, I feel sorry for you.
-
Max Lybbert about 12 yearsIt's entirely possible to call
count()
, save the result, and then pass the result toSLOT
ifSLOT
's not allowed to throw an exception. -
cgmb about 12 yearsSLOT does not take the result of count(). This is the SLOT macro:
# define SLOT(a) "1"#a
-
Petr over 10 years-1 for not providing any example how to reimplement this... all possible combinations I tried only throw some compiler errors and this information in this answer is basically something what we can see from qt debug log itself
-
Petr over 10 yearsWhat is MyApplication? Is that a dialog?
-
jichi over 10 yearsclass MyApplication : public QApplication
-
BЈовић over 10 yearsWhen it catches an exception, it returns true. Why? What does the return value mean? What if you return false?
-
jichi over 10 years@BЈовић I am not sure about the return value. According to Qt's documentation, it will determine whether propagate events (keyboard and mouse) to the parent. But for QApplication, I think it usually does not have a parent object.
-
cgmb about 10 yearsCatching it in the notify loop is a terrible way of handling exceptions because it results in an unintuitive control flow. If you really must, it's pretty simple and jichi's answer shows exactly how.
-
antred almost 9 yearsIn my opinion reimplementing QApplication::notify is by far the superior solution because it plugs all holes. After you've done this, you can be sure that any exception (at least any your catch-block mentions) will be caught and dealt with (perhaps log it to a file before exiting or something).
-
L__ almost 9 yearsthis doesn't really answer the question - in case you are using someone else's code you might want to use QApplication::notify to make sure you don't miss the exception
-
cgmb almost 9 years@antred QApplication already catches and logs the exception with a qWarning before exiting. That's the error message I quoted is. You probably want to save warnings to a log, and you can do so via qInstallMessageHandler. Though, yes, if you want to have a custom message, you'll need to reimplement
QApplication::notify
, -
cgmb almost 9 yearsIt's clear to me now that people finding this page are dealing with a variety of situations. The original answer was good for the asker, but I've updated my answer to try to address other situations that people may be facing.
-
Thomas about 3 yearsBut
receiver
might have a parent. It is the receivers hierarchy that matters for event propagation.