簡體   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