Qt/C++ Error handling

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 provide). One, in particular, provides for an unhandled exception which I use religiously. When the program encounters a problem, it throws the unhandled exception so that I can create my own error report. That report gets sent from my customers machine to a server online which I then read later.

The problem that I'm having with C++ is that any error handling that's done has to be thought of BEFORE hand (think try/catch or massive conditionals). In my experience, problems in code are not thought of before hand else there wouldn't be a problem to begin with.

Writing a cross-platform application without a cross-platform error handling/reporting/trace mechanism is a little scary to me.

My question is: Is there any kind of Qt or C++ Specific "catch-all" error trapping mechanism that I can use in my application so that, if something does go wrong I can, at least, write a report before it crashes?

Example:

class MainWindow: public QMainWindow
{
[...]

public slots:
 void add_clicked();
}

void MainWindow::add_clicked()
{
    QFileDialog dlg(this, Qt::Sheet);
    QString filename = dlg.getOpenFileName(this);

    if(!filename.isEmpty())
    {
        QStringList path = filename.split(QDir::separator());
        QString file = path.at(path.count()); // Index out of range assertion.

        if(!lst_tables->openDatabase(filename))
        {
            [...]
        }
    }
}

I want this error to be caught as an unhandled exception AND the application to quit without showing the user the default crash window on Windows/Mac operating system. I just want it to quit nicely after writing the assertion message to a file, etc.

Answers


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.


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
}

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...)


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!


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;
}

Need Your Help

How to export data with Oracle SQL Developer?

sql oracle oracle-sqldeveloper

How to export Oracle DB data using SQL Developer? I need all data, tables, constraints, structure and so on.

Automatically generate C# wrapper class from dll in Visual Studio 2010 Express?

c# dll wrapper visual-studio-express

I was told by a colleague of mine that Visual Studio allows one to point to a .dll and auto-magically generate a C# wrapper class. Is this really possible? And if so, how does one go about achievin...