[英]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.