2011-01-11 53 views
28

私はQt/C++でのエラー処理について多くの研究を行ってきました。たぶん私は簡単な方法を探しています(他の言語のように)。 1つは、特に、私が宗教的に使用する処理されない例外を提供します。プログラムで問題が発生すると、処理されない例外がスローされ、自分でエラーレポートを作成できます。そのレポートは、顧客のマシンからオンラインのサーバーに送信され、後で読むことができます。Qt/C++エラー処理

私がC++で抱えている問題は、実行されたエラー処理がすべて手作業であることを考えなければならないことです(try/catchまたは大量の条件を考える)。私の経験では、コードの問題は手前にあるとは考えられておらず、まずは問題がないでしょう。

クロスプラットフォームのエラー処理/レポート/トレースメカニズムを使用せずにクロスプラットフォームアプリケーションを作成することは私には少し怖いです。

私の質問は:QtやC++の特定の「catch-all」エラートラッピングメカニズムがありますか?私のアプリケーションで使用できるものがあります。何か問題が起きた場合は、少なくとも前にレポートを書くことができます。それはクラッシュする?

例:


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オペレーティングシステムのデフォルトのクラッシュ画面を表示せずに終了するためのアプリケーションとしてキャッチすることにしたいです。アサーションメッセージをファイルなどに書き込んだ後にうまく終了しないようにしてください。

答えて

28

QCoreApplication::notify()を上書きしてそこにtry-catchを追加してください。それは、main()内の何かが私の経験のほとんどのケースをカバーしています。

ここで私はそれをやっています。 Qtのバージョンではなく、ここではC++ RTTIを使用していますが、これは単にアプリケーションの利便性のためです。また、QMessageBoxには情報とログファイルへのリンクが付いています。あなたは自分の必要に応じて拡張する必要があります。我々はasyncronous例外(アクセス違反)をキャッチするために、Windows上で__try、__exceptを使用するほか

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

。 GoogleのBreakpadは、おそらくそのためのクロスプラットフォームの代替手段として役立つ可能性があります。

+0

私はそこにあなたのtry-catchの例を表示できますか? –

+0

@ShiGon:完了... – Macke

+0

私は自分がスローコマンドを使用する場合を除いて、私が何かtry-catchからの愛を得ていないので、何かが間違っていると思う。とても混乱します。それでもアプリケーションはクラッシュし、この場合Appleにエラーレポートを送信しようとします。私は正常に終了するアプリケーションを取得しようとしています。 –

10

あなたが(またはメインの周りにキャッチ(...)を置くことができる)ここで周りです:

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

また、Cスタイルの例外処理を追加すると、アクセス違反、スタックオーバーフローなど、いくつかの例外が発生します。 – Macke

+1

@Marcus MSVCを使用してWindows上での例外処理を介して、アクセス違反とスタックオーバーフローをキャッチすることはできますが、私は知っている限り...ポータブルではありません。 – rohanpm

+1

@Jerkface:True。私はなぜこの場合Windowsを想定していたのか分かりません。 : - | – Macke

5

Google Breakpadは、クロスプラットフォームのアプリケーション・エラー報告のフレームワークです。多分それは助ける?

(私はまだ私達のC++/QTのアプリでそれを試していないが、私はいつかそれに動き回るのが大好きです...)

2

Qtの一般使用していない、または完全にサポート例外投げ(!あなたはそれを信じことができる場合)

これらのリンクをチェックアウト:

Why doesn't Qt use exception handling?

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だ:

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

のみを使用:最後に

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

、ここでの実装例ですあなたのスロットから直接MACRO!