为什么QObject被销毁的信号在销毁之后才被调用?

13

考虑以下测试用例:

class MyObject : public QObject
{
    Q_OBJECT
public:
    MyObject() { qDebug() << "MyObject constructor"; }
    virtual ~MyObject() { qDebug() << "MyObject destructor"; }
};

class Tracker : public QObject
{
    Q_OBJECT
public:
    Tracker() {}

public slots:
    void onDestructor() { qDebug() << "About to be destroyed!"; }
};

int main(int argc, char** argv)
{
    QCoreApplication app(argc, argv);

    Tracker tracker;

    MyObject *obj = new MyObject();
    QObject::connect(obj, SIGNAL(destroyed()), &tracker, SLOT(onDestructor()));
    delete obj;

    return app.exec();
}

它打印出这个:

MyObject constructor
MyObject destructor
About to be destroyed!

这种行为与Qt文档相矛盾:"该信号在对象obj被销毁之前立即发出,无法被阻止。" 为什么会发生这种情况?

2个回答

30

如果你考虑信号的发射方式,它是由基类QObject完成的 - 这就是QObject知道它正在被销毁的方式。

因此,当派生类被销毁时,首先运行最终派生的析构函数(按照标准C++ dtor处理),并显示" MyObject析构函数"消息。当该析构函数完成时,将运行基础dtors,在这种情况下是QObject dtor,然后发出信号,并显示"即将被销毁!"消息。

你提到的文档措辞可能有点不够精确。可能更好地表达为"当对象obj被销毁时,发出此信号"或"在对象obj完全销毁之前立即发出此信号"之类的话。


2

如果使用直接连接,那么Michael的回答是正确的。

如果使用排队连接,则在下一次主事件循环的迭代中调用插槽。将其与发射信号的对象的析构函数相结合,就会变得明显,为什么结果与涉及直接连接的结果相同。

请参阅官方文档:

请注意,连接类型可能对多线程编程产生影响。 (简短版本:直接在与信号相同的线程中执行插槽,但排队在接收器线程中运行)


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