在执行插槽期间断开所有信号插槽连接是否会阻止所有后续插槽被调用?

Chr*_*ica 7 qt signals-slots

说我有一个Qt应用程序,我有这样的东西:

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

如果a()发出,B::b2()在断开所有插槽与A输入后仍然会调用插槽B::b1(),因为它们都响应相同的信号?假设两个对象都存在于同一个线程中,因此我们有直接连接.

我知道disconnect()断开所有来自A的信号连接,但我不确定发射是否只调度要调用的b1和b2插槽,然后调用它们,以便在两个插槽之前对连接的更改无效(因此,排放)返回.所以它可以实现如下:

emit:
  make temprorary copy of signal's slot table
  foreach element in temporary slot table: call

disconnect:
  clear signal's slot table
Run Code Online (Sandbox Code Playgroud)

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

Mic*_*urr 5

快速实验表明没有调用第二个插槽.

但是,我不确定这是否是Qt承诺的.

Qt确实记录了在连接接收器的迭代过程中进行的某些检查,但是这是非常宽松和非特定的(我在短搜索中没有遇到任何更好的事情); 来自http://doc.qt.io/qt-5/signalsandslots.html:

这是定位连接对象所需的开销,以安全地迭代所有连接(即检查后续接收器在发射期间是否未被破坏)

因此,他们松散地记录了在发出信号时进行的某些检查,例如接收器是否已被破坏.我认为检查连接是否已断开连接似乎是一种类似的情况,但如果明确记录它会很好.

因为听起来这对你来说是一个问题(你希望所有信号都通过,对吗?),你可以通过确保b1()最后连接信号到插槽来解决这个问题.Qt确实承诺将按连接顺序通过信号调用插槽,因此如果您安排将断开连接的插槽作为最后一个插槽,则将看到所有其他插槽.

我不知道这可能是多么容易安排,但是一个对象将从另一个对象的槽函数内部断开所有内容似乎有点奇怪(所以可能还有其他一些可以解决这个问题的重构).

如果这些都不可接受,那么为A具有您需要的行为的信号提供代理对象并不会太难.会有一个:

connect(A, SIGNAL(a()), proxy_obj, SLOT(proxy_slot()));
Run Code Online (Sandbox Code Playgroud)

将A的信号B连接到代理,然后可以连接到代理的信号(当代理的槽被调用时,代理将发出信号):

connect(proxy_obj, SIGNAL(a()), B, SLOT(b1()));
connect(proxy_obj, SIGNAL(a()), B, SLOT(b2()));
Run Code Online (Sandbox Code Playgroud)

由于A的断开连接不会影响代理与B的连接,因此代理将确保在A->a()发出信号时调用所有B的插槽.

class A_proxy : public QObject
{
    Q_OBJECT
public slots:
    void proxy_slot() {
        emit a();
    }

signals:
    void a();
};
Run Code Online (Sandbox Code Playgroud)