I\'ve been doing a lot of research about handling errors with Qt/C++ and I\'m still as lost as when I started. Maybe I\'m looking for an easy way out (like other languages p
Override QCoreApplication::notify() and add try-catch there. That, and something in main() covers most cases in my experience.
Here's sort-of how I do it. Note that I'm using C++ RTTI here, not Qt's version, but that's just for convenience in our apps. Also, we put up a QMessageBox with the info and a link to our log-file. You should expand according to your own needs.
bool QMyApplication::notify(QObject* receiver, QEvent* even)
{
try {
return QApplication::notify(receiver, event);
} catch (std::exception &e) {
qFatal("Error %s sending event %s to object %s (%s)",
e.what(), typeid(*event).name(), qPrintable(receiver->objectName()),
typeid(*receiver).name());
} catch (...) {
qFatal("Error <unknown> sending event %s to object %s (%s)",
typeid(*event).name(), qPrintable(receiver->objectName()),
typeid(*receiver).name());
}
// qFatal aborts, so this isn't really necessary
// but you might continue if you use a different logging lib
return false;
}
In addition we use the __try, __except on Windows to catch asyncronous exceptions (access violations). Google Breakpad could probably serve as a cross-platform substitute for that.
Qt doesn't generally use, or entirely support exception throwing (if you can belive that!)
Check out these links:
Why doesn't Qt use exception handling?
http://doc.qt.io/qt-5/exceptionsafety.html
That said, the answers from @Crazy Eddie and @Macke are pretty good, but don't always work. In particular, I found you can't use either of them from a slot function you've invoked from QML. So, I created a hacky work around for this problem. *Use this in conjunction with theirs - not in place of it.
First, I created class derived from QException, which I'll skip over here, but is something you'll probably want to do. In this post, I just refer to it as "MyQException".
Anyway, add this header for a class called QmlSlotThrower
:
#ifndef QMLSLOTTHROWER_H
#define QMLSLOTTHROWER_H
#include "MyQException.h"
class QmlSlotThrower
{
public:
static QmlSlotThrower *get()
{
static QmlSlotThrower instance;
return &instance;
}
QmlSlotThrower( QmlSlotThrower const& ) = delete;
void operator=( QmlSlotThrower const& ) = delete;
void throwToTop( const MyQException &exception );
private:
QmlSlotThrower(){}
};
static QmlSlotThrower *qmlSlotThrower = QmlSlotThrower::get();
#define throwFromQmlSlot( exc ) qmlSlotThrower->throwToTop( exc ); return;
#endif // QMLSLOTTHROWER_H
Then, it's cpp:
#include "QmlSlotThrower.h"
#include <QTimer>
class AsynchronousThrower: public QObject
{
Q_OBJECT
public:
void throwThis( const MyQException &exception )
{
exception_ = exception;
QTimer::singleShot( 0, this, SLOT( throwIt() ) );
}
private slots:
void throwIt(){ throw exception_; }
private:
MyQException exception_;
};
static AsynchronousThrower asycnThrower;
// This is needed to allow the Q_OBJECT macro
// to work in the private classes
#include "QmlSlotThrower.moc"
// --------------------------------
void QmlSlotThrower::throwToTop( const MyQException &exception )
{ asycnThrower.throwThis( exception ); }
Finally, here's an example implementation:
void someQMLSlot()
{
// Qt has been progressively adding exception handling
// support, but you still cannot throw from a QML
// triggered slot. It causes an uncatchable fatal error!
// As a general rule, don't throw in Qt unless you are
// certain something is there to catch it. You cannot
// count on an uncaught exception handler at a top level
// to always work. This QML problem is a perfect example.
// So this is not an option here!
//throw MyQException( "Something terrible occured!" );
// This work around, however, can be used instead!
//throwFromQmlSlot( MyQException( "Something terrible occured!" ) )
// Or, to be more robust in illustrating how you can still use
// normal throws from nested functions even, you can do this:
try{ throw MyQException( "Something terrible occured!" ); }
catch( const MyQException &e) { throwFromQmlSlot( e ) }
qDebug() << "YOU SHOULD NEVER SEE THIS!!";
}
ONLY USE THE MACRO DIRECTLY FROM YOUR SLOT!
You can put a catch (...) in or around main() Here's around:
int main() try
{
...
}
catch (std::exception & e)
{
// do something with what...
}
catch (...)
{
// someone threw something undecypherable
}
I prefer error handling using exceptions. Please find the below sample code:
ErrorStatus ExplodeToLine()
{
var errorStatus = new ErrorStatus();
try
{
errorStatus = fun();
if (!errorStatus.ok())
{
throw new VicException(L"fun failed");
}
errorStatus = fun1();
if (!errorStatus.ok())
{
throw new VicException(L"fun1 failed");
}
errorStatus = fun2();
if (!errorStatus.ok())
{
throw new VicException(L"fun2 failed");
}
errorStatus.setError(ErrorType.OK);
}
catch (VicException vicExp)
{
Log(vicExp.errorMsg());
}
catch (Exception exp)
{
Log(exp.errorMsg());
}
return error_status;
}
Google Breakpad is a cross-platform application error reporting framework. Maybe it helps?
(I haven't tried it in our c++/qt apps yet, but I'd love to get around to it someday...)