2012-04-09 650 views
12
try 
{ // `count()` throws exception 
    connect(thread, SIGNAL(started()), engine, SLOT(count())); 
} 
catch(const X& e) 
{} 

由於Qt的5,我得到以下錯誤:如何在Qt中捕捉異常?

Qt has caught an exception thrown from an event handler. Throwing exceptions from an event handler is not supported in Qt. You must not let any exception whatsoever propagate through Qt code. If that is not possible, in Qt 5 you must at least re-implement QCoreApplication::notify() and catch all exceptions there.

如果我不能趕上傳統的方式例外如上圖所示,然後在那裏是我們應該趕上那些?

+0

也許你應該把try-catch塊在count()函數。 .. – Kobe 2012-04-09 15:52:47

+0

#vBx計數拋出 – smallB 2012-04-09 15:55:49

+1

那麼你的解決方案提供的問題是好的 – Kobe 2012-04-09 15:58:22

回答

8

where am I supposed to catch it?

這就是爲什麼Qt不支持跨信號/插槽連接拋出異常。如果你嘗試,你會看到這樣一條消息:

Qt has caught an exception thrown from an event handler. Throwing exceptions from an event handler is not supported in Qt. You must reimplement QApplication::notify() and catch all exceptions there.

因爲它提到,有可能繼承的QApplication和趕上你的例外存在,但是這將是處理事情非常惱人的方式。

如果可能的話,我會建議重寫量,使得它不會拋出。


如果你不能重寫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。使用全局處理程序來處理全局問題是非常合理的。

+0

是的,我相信我必須重寫這個,不要扔。謝謝。 – smallB 2012-04-09 16:38:41

+0

完全可以調用'count()',保存結果,然後在SLOT不允許拋出異常的情況下將結果傳遞給'SLOT'。 – 2012-04-09 17:45:15

+0

SLOT不採用count()的結果。這是SLOT宏:'#define SLOT(a)「1」#a' – cgmb 2012-04-09 17:49:11

-8

你可以試試這個爲例,一看就知道你的解決方案是好的:

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

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

int main() 
{ 
    try { 
      g(f()); 
    }catch(int) 
    { 
     cout << "Caught exception" << endl; 
    } 
} 
+0

#vBx你不使用任何信號/插槽連接,我錯過了什麼? – smallB 2012-04-09 16:08:23

+0

@smallB:信號和插槽是QT特定的結構,vBx在這裏給你的是標準的C++解決方案。 – 2012-04-09 16:09:36

+0

@Als我看到了,但我的問題是特定於qt。我認爲信號插槽的概念將是一個很好的贈送。另外如果你會注意到我不問如何使用try catch塊。 – smallB 2012-04-09 16:21:35

6

如果有人需要一個示例代碼重寫的QApplication ::通知,我(在日本)得到了一個從這裏: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; 
} 
+0

什麼是MyApplication?這是一個對話框嗎? – Petr 2013-11-05 15:38:04

+1

class MyApplication:public QApplication – jichi 2013-11-05 18:27:53

+0

它的工作原理,謝謝 – Petr 2013-11-05 21:58:40