如果 QObject 与信号和插槽一起使用,则替换异常

Replacement for exceptions if QObject is used with Signal and Slots

我试图将我的问题分解为一个小例子。真正的问题是更复杂的沟通:

我有一个功能可以触发通信并连接并向服务器发送消息。如果有答案,Client-class 会发出包含答案的信号。

void communicate()
{
     client.setUpMessage(); // the answer is emitted as a signal and
                            // and processed in the Slot 
                            // 'reactToAnswer(...)'

     client.sendMessage("HelloWorld");
}

void reactToAnswer(QString answer)
{
     parser.parseAnswer() // an error could occur
}

如果在处理响应的槽中检测到错误怎么办?我想停止函数 communicate() 的执行。这意味着不应再执行函数 client.sendMessage("HelloWorld")

出于天真,我试图用异常处理问题:

void communicate()
{
     try
     {
          client.setUpMessage(); // the answer is emitted as a signal and
                                 // and processed in the Slot 
                                 // 'reactToAnswer(...)'

          client.sendMessage("HelloWorld");
      }
      catch(myException)
      {
           // do something
      }

void reactToAnswer(QString answer)
{
     if( !parser.parseAnswer() )
     {
          throw myException;
     }
}

这不起作用,从 qt 信号调用的插槽中抛出异常是未定义的行为。 usual way 是重新实现 QApplication::notify() resp。 QCoreApplication()::notify,但这对我不起作用。已经有一个用于 GUI 的 QApplication,我希望通信 class (QObject) 独立。所有的事情都应该在这个class之内处理。

我希望我能全面地解释问题。我不想在任何情况下使用异常,其他停止通信的方式也适合我。

提前致谢!

我不确定您要完成的工作是否特别适合信号与插槽范例...也许您只想使用常规的旧函数调用?即类似:

void communicate()
{
   QString theAnswer;  // will be written to by setupMessage() unless error occurs
   if (client.setUpMessage(theAnswer)) 
   {
      reactToAnswer(theAnswer);     
      client.sendMessage("HelloWorld");
   }
}

信号和槽不适合的原因是信号被设计为可以同时连接到多个槽,并且槽方法的调用顺序是未定义的——所以如果插槽方法试图以您描述的方式干扰信号发射过程,行为是相当不可预测的(因为您不知道有多少其他连接的插槽方法(如果有的话)已经作为信号发射,在你的特定插槽方法踩刹车之前)。当然,如果你去 queued/asynchronous 信号,那么它根本不会工作,因为在信号发射函数已经 return 很久之后,插槽将在完全不同的上下文中被调用编辑

就是说,如果您绝对必须为此使用信号和插槽,您可以让您的插槽发出自己的错误发生信号,该信号可以连接回原始信号发射中的插槽class。然后该插槽可以设置一个布尔值(或其他),然后您的 communicate() 方法可以检查该布尔值的状态(就在 client.setUpMessage() 具有 returned 之后)以决定是否继续执行或提早return。

(不过我不推荐——信号和槽的存在是为了让你的程序不那么复杂,在这种情况下我认为使用它们而不是常规的函数调用实际上会让你的程序更复杂,没有相应的好处)