繁体   English   中英

如何在exec循环停止后正确使用带QSharedPointer <QObject>的析构函数?

[英]How to properly use destructors with QSharedPointer<QObject> AFTER the exec loop is stopped?

大家,早安,

我正在使用QSharedPointer和我从QObject派生的类。 由于它们使用信号/槽机制,我必须使用QObject::deleteLater()才能正确销毁它们,例如参见:

~QObject() :“等待传递挂起事件时删除QObject会导致崩溃。如果QObject存在于与当前正在执行的线程不同的线程中,则不能直接删除它。使用deleteLater()代替,导致事件循环在所有挂起事件传递给它后删除对象。“

QSharedPointer和QObject :: deleteLater

QSharedPointer(X * ptr,Deleter d) :“删除器参数d指定此对象的自定义删除器。当强引用计数降为0时,将调用自定义删除器,而不是运算符delete()。这很有用,例如,用于在QObject上调用deleteLater()而不是“

另请注意,在上一个链接中,它是写的

“请注意,即使QSharedPointer模板参数T不相同,也会使用指向X类型的指针调用自定义删除函数。”,

但这与构造函数QSharedPointer(X * ptr)的行为完全不同,它表示:

“从Qt 5.8开始,当对这个QSharedPointer的最后一个引用被破坏时,ptr将通过调用X的析构函数来删除(即使X与QSharedPointer的模板参数T不同)。之前,T的析构函数被调用。” - (我使用Qt 5.7,所以我期待~T析构函数)

好吧,最后我想要实现的是使用QSharedPointer调用正确的析构函数(子类),但由于它是一个QObject我需要使用QObject::deleteLater() ,但在我的测试中我不是能够实现我的目标。

我发布了一个简单的测试和我的结果。

你能告诉我,如果我做错了吗?

我对测试的期望是正确的吗?

我对标有“有趣案例”的案件特别感兴趣

class A : public QObject
{
public:
    A() : QObject() {};
    virtual ~A() { qDebug() << "Destructor of A"; }
};

class B : public A
{
public:
    B() : A() {}
    ~B() { qDebug() << "Destructor of B"; }
};

int main(int argc, char*argv[])
{
    qDebug() << "QT version " << QT_VERSION_STR;

    qDebug() << "+++++++++++++++++++";
    {
        qDebug() << "Test: QSharedPointer<A> sp = QSharedPointer<A>(new A(), &QObject::deleteLater)";
        qDebug() << "Expected:";
        qDebug() << "Destructor of A";
        qDebug() << "Result:";
        QSharedPointer<A> sp = QSharedPointer<A>(new A(), &QObject::deleteLater);
    }
    qDebug() << "-------------------";

    qDebug() << "+++++++++++++++++++";
    {
        qDebug() << "Test: QSharedPointer<A> sp = QSharedPointer<A>(new A())";
        qDebug() << "Expected:";
        qDebug() << "Destructor of A";
        qDebug() << "Result:";
        QSharedPointer<A> sp = QSharedPointer<A>(new A());
    }
    qDebug() << "-------------------";

    qDebug() << "+++++++++++++++++++";
    {
        qDebug() << "Test: QSharedPointer<B> sp = QSharedPointer<B>(new B(), &QObject::deleteLater)";
        qDebug() << "Expected:";
        qDebug() << "Destructor of B";
        qDebug() << "Destructor of A";
        qDebug() << "Result:";
        QSharedPointer<B> sp = QSharedPointer<B>(new B(), &QObject::deleteLater);
    }
    qDebug() << "-------------------";

    qDebug() << "+++++++++++++++++++";
    {
        qDebug() << "Test: QSharedPointer<B> sp = QSharedPointer<B>(new B())";
        qDebug() << "Expected:";
        qDebug() << "Destructor of B";
        qDebug() << "Destructor of A";
        qDebug() << "Result:";
        QSharedPointer<B> sp = QSharedPointer<B>(new B());
    }
    qDebug() << "-------------------";

    qDebug() << "+++++++++++++++++++";
    {
        qDebug() << "INTERESTING CASE";
        qDebug() << "Test: QSharedPointer<A> sp = QSharedPointer<B>(new B(), &QObject::deleteLater)";
        qDebug() << "Expected:";
        qDebug() << "Destructor of B";
        qDebug() << "Destructor of A";
        qDebug() << "Result:";
        QSharedPointer<A> sp = QSharedPointer<B>(new B(), &QObject::deleteLater);
    }
    qDebug() << "-------------------";

    qDebug() << "+++++++++++++++++++";
    {
        qDebug() << "INTERESTING CASE";
        qDebug() << "Test: QSharedPointer<A> sp = QSharedPointer<B>(new B())";
        qDebug() << "Expected:";
        qDebug() << "Destructor of B";
        qDebug() << "Destructor of A";
        qDebug() << "Result:";
        QSharedPointer<A> sp = QSharedPointer<B>(new B());
    }
    qDebug() << "-------------------";

    qDebug() << "+++++++++++++++++++";
    {
        qDebug() << "Test: QSharedPointer<A> sp = QSharedPointer<A>(new B(), &QObject::deleteLater)";
        qDebug() << "Expected:";
        qDebug() << "Destructor of B";
        qDebug() << "Destructor of A";
        qDebug() << "Result:";
        QSharedPointer<A> sp = QSharedPointer<A>(new B(), &QObject::deleteLater);
    }
    qDebug() << "-------------------";

    qDebug() << "+++++++++++++++++++";
    {
        qDebug() << "IT SHOULD NOT WORK AS EXPECTED BEFORE QT 5.8, AS SPECIFIED IN QT DOCUMENTATION";
        qDebug() << "Test: QSharedPointer<A> sp = QSharedPointer<A>(new B())";
        qDebug() << "Expected:";
        qDebug() << "Destructor of B (NOT expected before Qt 5.8)";
        qDebug() << "Destructor of A";
        qDebug() << "Result:";
        QSharedPointer<A> sp = QSharedPointer<A>(new B());
    }
    qDebug() << "-------------------";
}

这就是结果:

QT version  5.7.1
+++++++++++++++++++
Test: QSharedPointer<A> sp = QSharedPointer<A>(new A(), &QObject::deleteLater)
Expected:
Destructor of A
Result:
-------------------
+++++++++++++++++++
Test: QSharedPointer<A> sp = QSharedPointer<A>(new A())
Expected:
Destructor of A
Result:
Destructor of A
-------------------
+++++++++++++++++++
Test: QSharedPointer<B> sp = QSharedPointer<B>(new B(), &QObject::deleteLater)
Expected:
Destructor of B
Destructor of A
Result:
-------------------
+++++++++++++++++++
Test: QSharedPointer<B> sp = QSharedPointer<B>(new B())
Expected:
Destructor of B
Destructor of A
Result:
Destructor of B
Destructor of A
-------------------
+++++++++++++++++++
INTERESTING CASE
Test: QSharedPointer<A> sp = QSharedPointer<B>(new B(), &QObject::deleteLater)
Expected:
Destructor of B
Destructor of A
Result:
-------------------
+++++++++++++++++++
INTERESTING CASE
Test: QSharedPointer<A> sp = QSharedPointer<B>(new B())
Expected:
Destructor of B
Destructor of A
Result:
Destructor of B
Destructor of A
-------------------
+++++++++++++++++++
Test: QSharedPointer<A> sp = QSharedPointer<A>(new B(), &QObject::deleteLater)
Expected:
Destructor of B
Destructor of A
Result:
-------------------
+++++++++++++++++++
IT SHOULD NOT WORK AS EXPECTED BEFORE QT 5.8, AS SPECIFIED IN QT DOCUMENTATION
Test: QSharedPointer<A> sp = QSharedPointer<A>(new B())
Expected:
Destructor of B (NOT expected before Qt 5.8)
Destructor of A
Result:
Destructor of B
Destructor of A
-------------------

编辑:

我知道QObject :: deleteLater的行为,特别是:

“如果在主事件循环停止后调用deleteLater(),则不会删除该对象。从Qt 4.8开始,如果在一个没有运行事件循环的线程中的对象上调用deleteLater(),则该对象将是线程结束时销毁。“

但是因为我使用的是Qt 5.7,所以无论如何我都希望在我的函数结束时调用析构函数,这是我开始的唯一线程(其他线程最终由Qt启动的部分)

编辑2

(我也编辑了标题)

(问题可能比我预期的要复杂得多。)

据我所知,没有主线。 所有线程都是相同的,也是应该使用main函数隐式创建的第一个线程。 它应该不是特别的,这是正确的吗?

那么,为什么退出主线程不会以正确的方式删除QSharedPointer

我发布的是一个测试,在我的实际应用程序中我有一个exec()循环,但是在循环停止后调用析构函数。

我希望然后在线程结束时调用deleteLater()函数,即当我退出主循环时。

PS:为了获得所有的析构函数,我需要一个exec()循环,正如@dave所说,但这将是我的应用程序中的第二个循环,即:

QTimer::singleShot(0, [](){qApp->exit();});
a.exec(); // a is my QApplication

return之前的最后。

为什么我需要它? 有可能避免它吗?

改为使用deleteLater(),这将导致事件循环在所有挂起事件传递给它之后删除该对象

您的程序中没有事件循环,因为没有QApplication对象。 因此,对deleteLater()所有调用都不会执行任何操作。

如果通过实例化QApplication并在其上调用exec来引入事件循环,您将看到正在调用的mising析构函数:

在main()的末尾:

QApplication a(argc, argv);
a.exec();

额外输出:

Destructor of A
Destructor of B
Destructor of A
Destructor of B
Destructor of A
Destructor of B
Destructor of A

编辑

由于已经有一个事件循环(如评论中所讨论的),问题是在事件循环结束 QSharedPointer对象被删除了。 (Aka exec()返回)

解决方法是将QCoreApplication::aboutToQuit信号与将删除QSharedPointer对象的函数或lambda连接起来。 (或者在这种情况下,清除包含这些的列表)

这样,事件循环有机会在完成之前破坏被指向的对象。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM