25
try
{  // `count()` throws exception
  connect(thread, SIGNAL(started()), engine, SLOT(count()));  
}
catch(const X& e)
{}

Qt-5 の時点で、次のエラーが発生します。

Qt は、イベント ハンドラーからスローされた例外をキャッチしました。Qt では、イベント ハンドラーからの例外のスローはサポートされていません。いかなる例外も Qt コードを通じて伝播させてはなりません。それが不可能な場合は、Qt 5 で少なくとも再実装 QCoreApplication::notify()してすべての例外をキャッチする必要があります。

上記のように従来の方法で例外をキャッチできない場合、どこでキャッチすればよいのでしょうか?

4

3 に答える 3

20

どこで捕まえればいいの?

これがまさに、Qt がシグナル/スロット接続を介した例外のスローをサポートしていない理由です。試してみると、次のメッセージが表示されます。

Qt は、イベント ハンドラーからスローされた例外をキャッチしました。Qt では、イベント ハンドラーからの例外のスローはサポートされていません。QApplication::notify() を再実装し、そこですべての例外をキャッチする必要があります。

言及されているように、QApplication をサブクラス化してそこで例外をキャッチすることは可能ですが、それは物事を処理する非常に面倒な方法になります。

可能であれば、スローしないように count を書き換えることをお勧めします。


count() を書き換えられない場合はどうなりますか?

たとえば、count() が、使用しているサードパーティ ライブラリの関数の一部である場合はどうなるでしょうか?

公式の Qt ライブラリにはスロットがスローされないため、スロットがスローされるサードパーティ製ライブラリを使用している場合は、それが適切なライブラリではないことを示している可能性があります。とにかく使いたい場合は、 でキャッチするのではなく、QApplication::notify代わりにアダプターを作成することをお勧めします。

どういう意味ですか?まず、大ざっぱなサードパーティ オブジェクトをコンストラクターに取り込むオブジェクトを作成します。その中に、try/catch ブロックを使用してスローするスロットへの呼び出しをラップするスロットを記述します。大ざっぱなサードパーティ オブジェクトのスロットに接続する代わりに、新しく作成したオブジェクトのスロットに接続します。

QApplication::notifyこのように例外をキャッチすると、関連するコードがまとめられ、これらの問題のある関数が複数発生した場合に、無関係な try/catch ブロックの束でいっぱいになるのを防ぎます。

例えば:

class BadCounter {
Q_OBJECT
public slots:
  void count() { throw CounterError("unable to count"); }
};

class CounterAdaptor {
Q_OBJECT
  BadCounter* counter_;
public:
  CounterAdaptor(BadCounter* counter) {
    counter_ = counter;
  }
public slots:
  void count() {
    try {
      counter_->count();
    } catch (const CounterError& e) {
      std::cerr << e.what() << std::endl;
    }
  }
};

int main() {
  BadCounter engine;
  CounterAdaptor adaptor(&engine);
  QThread* thread = new QThread();
  connect(thread,SIGNAL(started()),&adaptor,SLOT(count())); 
  thread.start();
  ... // etc...
  delete thread;
}

どこからでも投げられる可能性のあるものを処理したい場合はどうしますか?

この種のグローバルな懸念の明白な例は、予期しない例外です。間違いはどこでも起こりえます。原因を特定して修正できるように、イベントに関するできるだけ多くの詳細をログに記録することが望ましいでしょう。この場合、jichi's answerに示されているように、独自のサブクラスで再実装する必要があります。グローバルな問題に対してグローバル ハンドラを使用することは、非常に合理的です。QApplication::notify

于 2012-04-09T16:30:03.463 に答える
16

QApplication::notify をオーバーライドするサンプル コードが必要な場合は、ここ (日本語) から入手しました: http://www.02.246.ne.jp/~torutk/cxx/qt/QtMemo.html

#include "MyApplication.h"
#include <exception>

MyApplication::MyApplication(int& argc, char** argv) :
  QApplication(argc, argv) {}

bool MyApplication::notify(QObject* receiver, QEvent* event) {
  bool done = true;
  try {
    done = QApplication::notify(receiver, event);
  } catch (const std::exception& ex) {
    // ログや何らかの回復処理
  } catch (...) {
    // ログや何らかの回復処理
  }
  return done;
} 
于 2013-02-11T01:29:42.767 に答える
-11

例としてこれを試して、ソリューションが優れていることを確認できます。

int f()
{
    throw 1;
    return 5;
}

void g(int x)
{
    cout << x << endl;
}

int main()
{
    try {
            g(f());
    }catch(int)
    {
        cout << "Caught exception" << endl;
    }
}
于 2012-04-09T15:59:59.830 に答える