c++ - 执行循环停止后如何正确使用 QSharedPointer<QObject> 的析构函数?

标签 c++ qt destructor qobject qsharedpointer

大家早上好

我将 QSharedPointer 与派生自 QObject 的类一起使用。由于它们使用信号/槽机制,我必须使用 QObject::deleteLater() 才能正确销毁它们,例如:

~QObject() :“在等待传递未决事件时删除 QObject 可能会导致崩溃。如果 QObject 存在于与当前正在执行的线程不同的线程中,则不能直接删除它。请改用 deleteLater(),这将导致事件循环在所有未决事件都传递给对象后删除该对象。”

QSharedPointer and QObject::deleteLater

QSharedPointer(X *ptr, Deleter d) :“删除器参数 d 指定此对象的自定义删除器。当强引用计数下降到 0 时,将调用自定义删除器,而不是运算符 delete()。这很有用,例如,调用 deleteLater()取而代之的是 QObject”

另请注意,在 previous link 中写着

“请注意,将使用指向类型 X 的指针调用自定义删除函数,即使 QSharedPointer 模板参数 T 不同。”,

但这与构造函数的行为完全不同 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 之前的最后。

为什么我需要它?有可能避免吗?

最佳答案

Use deleteLater() instead, which will cause the event loop to delete the object after all pending events have been delivered to it.

您的程序中没有事件循环,因为没有QApplication 对象。因此,所有对 deleteLater() 的调用都不会执行任何操作。

如果您通过实例化 QApplication 并对其调用 exec 来引入事件循环,您将看到调用了错误的析构函数:

在 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 对象在事件循环已经完成后被删除了。 (又名 exec() 返回)

解决方案是连接 QCoreApplication::aboutToQuit使用将删除 QSharedPointer 对象的函数或 lambda 发出信号。 (或者在这种情况下,清除包含这些的列表)

这样,事件循环就有机会在完成之前销毁所指向的对象。

关于c++ - 执行循环停止后如何正确使用 QSharedPointer<QObject> 的析构函数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54628626/

相关文章:

c++ - 在 hashmap/unordered_map 中,当 value 已经包含 key 时,是否可以避免数据重复

c++ - 没有匹配函数来调用 'CFastLED::addLeds(CRGB [6], int)

qt - 将 PySide/PyQt 小部件嵌入到 Qt/C++ 应用程序中

c++ - 如何在 SQLite 数据库中存储枚举

c++ - 创建了我自己的字符串类——重载赋值运算符和析构函数的错误

c++ - 删除外部类实例中的内部类实例

python - 在 Python 中依赖 __del__() 进行清理不可靠吗?

c++ - 如何编写写入/var/log/myapp 目录的 C/C++ 应用程序?

C++抽象基类集合

c++ - 对象创建的外包