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