4

おはようございます。

QSharedPointerから派生したクラスで使用していますQObject。これらはシグナル/スロット メカニズムを使用するQObject::deleteLater()ため、適切に破棄するには を使用する必要があります。例を参照してください。

~QObject() : "保留中のイベントが配信されるのを待っているときに 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 への最後の参照が破棄されると、ptr は X のデストラクタを呼び出すことによって削除されます (X が QSharedPointer のテンプレート パラメータ T と同じでなくても)。以前は、T のデストラクタが呼び出されていました。」- (私は Qt 5.7 を使用しているので、~Tデストラクタを期待しています)

さて、最後に達成したいのは、を使用して(子クラスの)適切なデストラクタを呼び出すQSharedPointerことですが、それはQObjectを使用する必要があるためQObject::deleteLater()、テストでは目標を達成できません。

簡単なテストと結果を投稿します。

私が何か間違ったことをしている場合は教えていただけますか?

テストに期待することは正しいですか?

私が特に興味を持っているのは、「INTERESTING CASE」と書かれたケースです。

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を使用しているので、関数の最後にデストラクタが呼び出されることを期待しています.

編集 2

(タイトルも編集しました)

(質問は、予想以上に複雑になっているかもしれません。)

私の知る限り、メインスレッドはありません。すべてのスレッドは同等であり、メイン関数で暗黙的に作成される最初のスレッドでもあります。決して特別なものではないはずですよね?

では、なぜメイン スレッドを終了してもQSharedPointers が適切な方法で削除されないのでしょうか。

私が投稿したのはテストです。実際のアプリケーションではexec()ループがありますが、ループが停止した後にデストラクタが呼び出されます。

deleteLater()スレッドが終了したとき、つまりメインループを終了したときに s 関数が呼び出されることを期待しています。

PS: exec()@dave が言ったように、すべてのデストラクタを取得するためにループが必要でしたが、これはアプリケーションの 2 番目のループになります。

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

最後に の直前にreturn

なぜ必要なのですか?それを避けることは可能ですか?

4

1 に答える 1