3

在查看一些代码时,我发现了这样一段代码:

struct MyFooStructure
{
  //Nothing unusual, just basic types
}

class Foo : public QObject
{
   Q_Object

public:
   void fooMethod(const MyStructure &s);

signals:
   void fooSignal(const MyStructure &);
}

void Foo::fooMethod(const MyStructure &s)
{
   try
   {
      emit fooSignal(s)
   }
   catch(const std::exception &e)
   {
      qDebug() << "An exception!";
   }
}

有没有可能进入这里的渔获?据我所知,没有可能引发异常:emit 只是一个宏,用于创建一个表以调用连接到 *.moc 文件上的该信号的适当函数。真的需要try catch吗?

4

1 回答 1

6

是的,在您的示例中需要捕获,至少如果有任何插槽连接到fooSignal抛出std::exception.

该语句emit fooSignal();同步调用所有连接的插槽。基本上QObject内部有一个连接表,其中存储了一个对象的所有连接,每个插槽都是一个函数指针。基本上做什么emit(或者更确切地说,moc 生成的实现做什么fooSignal)是它简单地遍历连接表并为每个连接的插槽调用所有函数指针。

所以插槽是从 connect 语句中调用。这也意味着如果任何插槽抛出异常,异常将传播到emit语句之外。

请注意,内部 moc 生成的代码fooSignal仅是最近的异常安全代码,请参阅 Olivier对此错误报告的回答。这意味着旧版本的 Qt 无法处理插槽中抛出的异常,如果插槽抛出异常,moc 生成的代码将以未定义的方式失败。

编辑:我还想补充一点,有抛出异常的插槽是不好的做法,尽量避免这种做法。调用的代码emit不知道连接了哪些插槽,因此它不知道需要捕获哪些异常。此外,一旦您有排队连接而不是直接连接,插槽将被异步调用而不是同步调用,您将无法捕获插槽的异常。

于 2013-06-19T21:52:11.007 回答