Qt/C++错误处理

sqserrrh  于 2023-05-08  发布在  其他
关注(0)|答案(5)|浏览(200)

我已经做了很多关于用Qt/C处理错误的研究,但我仍然和刚开始时一样迷茫。也许我正在寻找一个简单的方法(像其他语言提供)。特别是其中一个,它提供了一个未处理的异常,我虔诚地使用它。当程序遇到问题时,它会抛出未处理的异常,这样我就可以创建自己的错误报告。该报告从我的客户机器发送到在线服务器,然后我稍后阅读。
我在使用C
时遇到的问题是,任何错误处理都必须事先考虑(想想try/catch或大量条件)。根据我的经验,代码中的问题是事先没有想到的,否则就不会有问题。
编写一个没有跨平台错误处理/报告/跟踪机制的跨平台应用程序对我来说有点可怕。
我的问题是:是否有任何一种Qt或C++特定的“捕获所有”错误捕获机制,我可以在我的应用程序中使用,这样,如果确实出了问题,我至少可以在它崩溃之前写一个报告?
示例:

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))
        {
            [...]
        }
    }
}

我希望这个错误被捕获为一个未处理的异常和应用程序退出,而不向用户显示Windows/Mac操作系统上的默认崩溃窗口。我只是希望它在将Assert消息写入文件等之后能够很好地退出。

wtzytmuj

wtzytmuj1#

重写QCoreApplication::notify()并在其中添加try-catch。这一点,以及main()中的一些东西涵盖了我的经验中的大多数情况。
我是这么做的请注意,我在这里使用的是C++ RTTI,而不是Qt的版本,但这只是为了方便我们的应用程序。此外,我们还提供了一个包含信息的QMessageBox和一个指向我们日志文件的链接。你应该根据自己的需要进行扩展。

bool QMyApplication::notify(QObject* receiver, QEvent* event)
{
    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;
}

此外,我们在Windows上使用__try__except来捕获异步异常(访问冲突)。Google Breakpad可以作为跨平台的替代品。

yhxst69z

yhxst69z2#

你可以在main()中或周围放置一个catch(...)

int main() try
{
  ...
}
catch (std::exception & e)
{
  // do something with what...
}
catch (...)
{
  // someone threw something undecypherable
}
xggvc2p6

xggvc2p63#

Google Breakpad是一个跨平台的应用程序错误报告框架。也许会有帮助
(我还没有在我们的c++/qt应用程序中尝试过它,但我希望有一天能找到它。

sbdsn5lh

sbdsn5lh4#

Qt通常不使用或完全不支持异常抛出(如果你相信的话!))
看看这些链接:
Why doesn't Qt use exception handling?
http://doc.qt.io/qt-5/exceptionsafety.html
也就是说,“疯狂的埃迪”和“麦克”的答案很不错,但并不总是有效。特别是,我发现从QML调用的slot函数中不能使用它们中的任何一个。所以,我为这个问题创建了一个hacky工作。* 将此与他们的一起使用-而不是代替它。
首先,我创建了从QException派生的类,这里我将跳过它,但这可能是您想要做的事情。在这篇文章中,我只是把它称为“MyQException”。
无论如何,为一个名为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

然后,是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 ); }

最后,这里是一个示例实现:

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

只能直接从您的插槽中使用宏!

sz81bmfz

sz81bmfz5#

我更喜欢使用异常处理错误。请查看下面的示例代码:

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

相关问题