发出Qt信号时是否有可能抛出异常?

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

在这里有进入catch的可能性吗?据我所知,没有可能抛出任何异常:emit只是一个宏,用于创建一个表格,在*.moc文件中调用与该信号连接的适当函数。那么,真的需要try catch吗?


你可以查看自动生成的(moc)代码来确定它是否会抛出异常。例如,moc_something.cpp等。从我所见到的很少内容来看,我没有看到任何异常情况。 - Son-Huy Pham
1
@Huytard 但是由于信号的结果而调用的函数/插槽可能会抛出异常。 - nos
1个回答

6
在您的示例中,如果任何连接到 fooSignal 的插槽抛出 std::exception,则需要使用 catch。
语句 emit fooSignal(); 同步调用所有连接的插槽。基本上,QObject 在内部具有连接表,其中存储了对象的所有连接,每个插槽都是函数指针。基本上,emit 做的事情(或者更确切地说,fooSignal 的 moc 生成的实现所做的事情)就是简单地遍历连接表,并为每个连接的插槽调用所有函数指针。
因此,插槽从 connect 语句“内部”调用。这也意味着,如果任何插槽引发异常,该异常将传播到 emit 语句之外。
请注意,fooSignal 的内部 moc 生成的代码仅在最近才具有异常安全性,请参见 Olivier 在 this bug report 上的答案。这意味着旧版本的 Qt 无法处理插槽中引发的异常,如果插槽引发异常,moc 生成的代码将以未定义的方式失败。

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


因此澄清一下:emit背后的Qt内部代码不会抛出异常,但连接的槽可能会。 - Thomas McGuire
同意。据我所知,Qt本身从不抛出异常。 - confusopoly
如果你想保持安全:除非有明确的文档说明,否则不要让异常通过Qt代码冒泡。 - peppe

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接