15

当 QObject 派生对象被破坏时,是否可以从其析构函数发出信号?我试过了,它似乎可以工作,但我不确定是否应该这样做。

例如,这段代码

class MyClass : public QObject {
signals:
    void mySignal(const QString &str);
public:
    QString myString;
    ~MyClass() { emit mySignal(myString); }
}

将传递一个 const 引用到执行连接插槽时可能超出范围的对象。

4

2 回答 2

14

发射通常很好(QObject 也使用“破坏”信号),包括你的情况。当连接是直接的时,字符串仍然存在。而当它是QueuedConnection 时,则首先将字符串复制到事件循环中。

于 2012-12-24T19:14:37.493 回答
5

如果您问是否可以:可以,它本身不会引起任何问题。

如果您要问在 Qt 中做这件事是否普遍安全?绝对不安全。如果你从析构函数发出,你必须非常注意你所做的事情,并且对 Qt 事件系统有很好的理解。

还记得当QObject后代销毁时,它会断开所有信号,因此被销毁的对象不会在其插槽上获得更多调用?好吧,有一个问题:销毁命令。析构函数会断开连接,并且它是最后一个QObject析构函数,这意味着在析构链中,事件可能仍会到达“半死”对象,从而在访问虚函数和已析构后代的成员时导致访问冲突。如果您使用事件系统,并且满足以下任何条件,则存在这种可能性:

  • 在多线程环境中,如果对象没有在自己的线程上被破坏。
  • 在多线程环境中,如果对象的销毁链触发了 aprocessEvents()在任意运行路径上的运行。
  • 在多线程环境中,如果另一个线程上的任何对象与该对象有直接连接,并且它无法对其直接连接中的破坏信号做出反应。
  • 在单线程环境中,当析构函数发送可能返回到直接连接链中的对象的信号时。

我将此效果称为“死亡期间的生命”,并且processEvents()在析构函数中发出信号或运行任何形式的(通常是意外的)都会增加产生此类错误的机会。

当然,如果你能以某种方式保证在销毁期间没有任何当前或未来的代码实际上会触发任何插槽,那么从析构函数发出它是完全安全的,但是很难给出这样的保证,我建议尽可能避免它.

于 2017-02-16T09:13:15.703 回答