2012-04-09 997 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