【问题标题】:Is it OK to emit a signal from an object's destructor in Qt?在 Qt 中从对象的析构函数发出信号可以吗?
【发布时间】:2012-12-11 02:02:37
【问题描述】:

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

比如这段代码

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

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

【问题讨论】:

    标签: c++ qt


    【解决方案1】:

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

    【讨论】:

    • 但是我假设 sender() 方法可以给出一个无效的指针?无论如何,我认为在编写插槽时我应该小心并牢记这一点。
    • 是的,当然。如果你有一个排队的连接,如果信号是在 dtor 中发出的,你就不能使用 sender() 。信号的接收者必须意识到这一点。
    • @JohannesSchaub-litb 这真的普遍吗?为什么?想象一个对象必须在某处(取消)注册自己并获得回调的情况。数据尚未公布。我必须确保发出这个信号是直接连接,在 dtor 的开头发出,派生类会中断,但回调会正常工作吗?
    【解决方案2】:

    如果你问是否OK:是的,它本身不会造成任何问题。

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

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

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

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-01-05
      • 2012-07-23
      • 1970-01-01
      • 1970-01-01
      • 2011-08-12
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多