大家,早安,
我正在使用QSharedPointer
我的类派生自QObject
. 由于它们使用信号/插槽机制,我必须使用QObject::deleteLater()
才能正确销毁它们,例如:
~QObject():“在等待传递的未决事件时删除 QObject 可能会导致崩溃。如果 QObject 存在于与当前执行的线程不同的线程中,则不得直接删除它。请改用 deleteLater(),这将导致事件循环在所有未决事件都传递给它之后删除该对象。”
QSharedPointer 和 QObject::deleteLater
QSharedPointer(X *ptr, Deleter d) : "deleter 参数 d 指定此对象的自定义删除器。当强引用计数降至 0 时,将调用自定义删除器,而不是运算符 delete()。这很有用,例如,改为在 QObject 上调用 deleteLater()"
另请注意,在上一个链接中它是这样写的
"请注意,即使 QSharedPointer 模板参数 T 不一样,也会使用指向 X 类型的指针调用自定义删除器函数。",
但这与构造函数QSharedPointer(X *ptr)的行为完全不同,它说:
“从 Qt 5.8 开始,当对这个 QSharedPointer 的最后一个引用被销毁时,将通过调用 X 的析构函数来删除 ptr(即使 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
以正确的方式删除 s 呢?
我发布的是一个测试,在我的真实应用程序中我确实有一个exec()
循环,但是在循环停止之后调用析构函数。
我希望deleteLater()
在线程结束时调用 s 函数,即当我退出主循环时。
PS:为了获得所有的析构函数,我需要一个exec()
循环,正如@dave 所说,但这将是我应用程序中的第二个循环,即:
QTimer::singleShot(0, [](){qApp->exit();});
a.exec(); // a is my QApplication
最后就在return
.
为什么我需要它?有可能避免吗?