在执行一个slot时,断开所有的信号槽连接是否会阻止所有后续的slots被调用?

8

假设我有一个Qt应用程序,其中有以下内容:

connect(A, SIGNAL(a()), B, SLOT(b1()));
connect(A, SIGNAL(a()), B, SLOT(b2()));
...
void B::b1() {
  A->disconnect();
}

如果发出了调用a()的信号,那么在B::b1()中断开所有与A连接的槽之后,槽B::b2()是否仍然会被调用?因为它们都响应于同一个信号。假设这两个对象都在同一个线程中,因此我们有一个直接连接。
我知道disconnect()将断开所有与A的信号连接,但我不确定emit是否只是计划调用b1和b2槽,然后调用它们,以便对连接进行更改,直到两个槽(因此是emit)返回。所以它可以实现如下:
emit:
  make temprorary copy of signal's slot table
  foreach element in temporary slot table: call

disconnect:
  clear signal's slot table

否则,您可能会遇到数据结构完整性问题。

作为一个相关的注释,Qt的foreach实际上会对其操作的列表进行临时复制。如果只是在表格上执行Qt foreach,则不会出现数据完整性问题。 - cgmb
如果是这样的话,那就完全符合我的解决方案了,然后第二个插槽将被调用。但我想元对象系统可能会更加复杂。 - Christian Rau
2个回答

6
一项快速实验表明第二个插槽未被调用。
但是,我不确定这是否是Qt所承诺的。
Qt确实记录了在连接接收器的迭代过程中进行了某些检查,但这是相当松散和非特定的(在我的短暂搜索中,我没有找到更好的内容);来自http://doc.qt.io/qt-5/signalsandslots.html
这是定位连接对象、安全地迭代所有连接所需的开销(即检查在发射期间后续接收器是否已被销毁)。
因此,他们宽泛地记录了在信号发射时进行了某些检查,例如接收器是否已被销毁。我认为检查连接是否已断开似乎是类似的情况,但如果明确记录这一点将会很好。

由于这听起来对你来说可能会成为一个问题(你想让所有信号都通过,对吧?),你可以通过确保连接到slot b1()的信号最后一个被连接来解决这个问题。Qt承诺按连接顺序调用slot,因此如果您安排执行断开连接的slot是最后一个,那么所有其他slot将被看到。

我不知道这有多容易安排,但另外一件奇怪的事情是,一个对象会从另一个对象的slot函数内部断开所有连接(因此可能还有其他重构可以解决这个问题)。

如果以上方法都不可接受,很容易为A的信号设计一个代理对象,具有您所需的行为。 这将是单一的:

connect(A, SIGNAL(a()), proxy_obj, SLOT(proxy_slot()));

将A的信号连接到代理,然后B可以连接到代理的信号(当代理的槽被调用时,代理将发出该信号):
connect(proxy_obj, SIGNAL(a()), B, SLOT(b1()));
connect(proxy_obj, SIGNAL(a()), B, SLOT(b2()));

由于 A 的断开不会影响代理与 B 的连接,代理将确保在信号 A->a() 发射时,调用所有 B 的插槽。
class A_proxy : public QObject
{
    Q_OBJECT
public slots:
    void proxy_slot() {
        emit a();
    }

signals:
    void a();
};

好的,我应该试一试。对于这个行为是否得到保证并不太重要,因为现在我知道我的解决方案并不能保证始终有效,谢谢。 - Christian Rau
实际上,我已经想出了一个解决方法,它并不是很复杂(有点类似于你的代理解决方案)。但当它们按连接顺序调用时(我不知道这一点,可能是我看漏了),这对我也有效,因为修改插槽总是最后连接的。再次感谢您详细的答复。 - Christian Rau

-3

断开参考页面 可以回答你的问题。

这取决于你如何调用它,以及你如何调用它(没有任何参数),它将断开对象 A 上的所有信号,因此在断开后不会调用槽 B:b2。


我理解disconnect的作用,只是不确定A::a()的emit是否会先安排b1和b2被调用,然后再调用它们,所以在emit返回之前断开连接并没有任何区别。 - Christian Rau
2
这并没有回答问题。它们断开连接并不意味着第二个插槽的调用在断开连接之前没有排队。 - Matthew Read

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