Qt / C ++ Обработка ошибок - PullRequest
30 голосов
/ 11 января 2011

Я проводил много исследований об обработке ошибок с помощью Qt / C ++, и я все еще потерян, как и при запуске.Может быть, я ищу легкий выход (как и на других языках).Одно, в частности, предусматривает необработанное исключение, которое я использую неукоснительно.Когда программа сталкивается с проблемой, она генерирует необработанное исключение, чтобы я мог создать свой собственный отчет об ошибке.Этот отчет отправляется с моего компьютера клиента на сервер в сети, который я затем читаю позже.

Проблема, с которой я сталкиваюсь в C ++, заключается в том, что любая обработанная ошибка должна рассматриваться ДО руки (подумайте, попробуйте/ улов или массовые условности).По моему опыту, о проблемах в коде не думали раньше, иначе не было бы проблем с самого начала.

Написание кроссплатформенного приложения без кросс-платформенного механизма обработки ошибок / создания отчетов / трассировкинемного страшно для меня.

Мой вопрос: есть ли какой-нибудь специфичный для 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.Я просто хочу, чтобы он правильно завершился после записи сообщения подтверждения в файл и т. Д.

Ответы [ 5 ]

31 голосов
/ 11 января 2011

Переопределить QCoreApplication :: notify () и добавить туда try-catch.Это и что-то в main () охватывает большинство случаев из моего опыта.

Вот как я это делаю.Обратите внимание, что я использую C ++ RTTI, а не версию Qt, но это просто для удобства в наших приложениях.Также мы создаем QMessageBox с информацией и ссылкой на наш лог-файл.Вы должны расширяться в соответствии с вашими потребностями.

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

Кроме того, мы используем __try, __except в Windows, чтобы перехватывать асинхронные исключения (нарушения доступа).Google Breakpad, вероятно, может служить кроссплатформенной заменой этому.

10 голосов
/ 11 января 2011

Вы можете поместить поймать (...) в или вокруг main () Вот что:

int main() try
{
  ...
}
catch (std::exception & e)
{
  // do something with what...
}
catch (...)
{
  // someone threw something undecypherable
}
5 голосов
/ 12 января 2011

Google Breakpad - это платформа кросс-платформенных отчетов об ошибках приложений. Может это поможет?

(я еще не пробовал это в наших приложениях c ++ / qt, но я бы хотел когда-нибудь обойти это ...)

2 голосов
/ 28 января 2017

Qt обычно не использует или не поддерживает исключение (если вы можете в это поверить!)

Проверьте эти ссылки:

Почему Qt не использует исключенияобработка?

http://doc.qt.io/qt-5/exceptionsafety.html

Тем не менее, ответы @Crazy Eddie и @Macke довольно хороши, но не всегда работают.В частности, я обнаружил, что вы не можете использовать ни одну из них из функции слота, которую вы вызывали из QML.Итак, я создал хакерское решение этой проблемы.* Используйте это вместе с их - не вместо этого.

Сначала я создал класс, производный от 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!!";
}

ТОЛЬКО ИСПОЛЬЗУЙТЕ МАКРО ПРЯМО С ВАШЕГО СЛОТА!

0 голосов
/ 11 апреля 2019

Я предпочитаю обработку ошибок с использованием исключений. Пожалуйста, найдите приведенный ниже пример кода:

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;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...