何时使用deleteLater

use*_*708 13 qt message-queue

假设我有以下代码段,在qto的析构函数中调用deleteLater是否可以安全地管理它可能管理的其他QT对象?

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);

    MyQTObject qto;
    qto.show();
    return a.exec();
}
Run Code Online (Sandbox Code Playgroud)

因为我用泄漏检测器分析了类似的代码,并且调用了deleteLater的所有对象都没有正确释放,除非我用普通删除替换了调用.如果我已正确理解这一点,则deleteLater仅在QT消息​​队列中注册删除事件.这可能是在main的范围结束时调用qto的析构函数的问题,而QT消息循环已经从a.exec的返回结束了吗?因此,永远不会处理删除事件,实际上甚至没有被推入消息队列,因为没有?

Eme*_*pon 12

这篇文章相当老化,但我想补充一下,当我自己问这个问题时,我希望得到的答案.

deleteLater()与异步操作结合使用非常有用.我认为,它最近可能会将信号连接到lambda函数.

假设您有一些longComputation()想要异步执行的(不是在多线程意义上,在事件循环中调度执行的意义上).你可以这样做:

void MyClass::deferLongComputation()
{
    QTimer* timer = new QTimer();

    connect(timer, 
            &QTimer::timeout,
            [this, timer](){this->longComputiation(); timer->deleteLater();});

    timer->setSingleShot(true);
    timer->start();
}
Run Code Online (Sandbox Code Playgroud)

一旦完成其职责,deleteLater()就要注意安全地处理,QTimer并避免人们本来会发生的内存泄漏.

相同的模式可用于多线程QFutureWatcher.


The*_*ght 10

据我了解,当您需要从对插槽的调用中删除对象时,最常使用deleteLater.如果在这种情况下使用delete并且从插槽返回时引用了对象,则会发生对未初始化内存的引用.

因此,deleteLater通过在事件循环上放置一条消息来请求删除该对象,该消息在某个时刻处理,从插槽返回时可以安全删除.

我希望在析构函数中使用deleteLater意味着对象可能超出范围,在其托管对象上调用deleteLater,但在事件循环有机会删除对象之前退出,退出QApplication :: exec( )将终止事件循环.


Win*_*lds 5

这个问题很老了,但我会把这个留给后代)被标记为答案的回复是正确的,但表达方式很奇怪。实际上,您的问题包含正确答案:

消息循环已经以 a.exec 的返回结束?因此删除事件永远不会被处理,事实上甚至不会被推送到消息队列中,因为没有消息队列。

这正是正在发生的事情。所做的一切deleteLater()只是将删除事件发布到外部事件循环中。当事件被处理时 - 对象被删除。但是如果没有外部事件循环并且在执行流程的后面没有遇到事件循环 - 事件永远不会被发布,因此对象永远不会被删除。

如果您调用deleteLater()对象的析构函数并将对象放在堆栈上 -deleteLater()当对象超出范围时调用。在您的示例中,当main()遇到关闭函数大括号时,就会发生“超出范围” 。然而,到那个时候,a.exec()(它代表 Qt App 的主事件循环)已经返回-->不再有事件循环--> deleteLater()被调用,但它无处发布删除事件-->对象应该是“deletedLater”永远不会被删除......

关于“何时使用 deleteLater()”部分:

库巴·奥伯回答:

一般来说,应该使用deleteLater 的情况非常有限。很可能你根本不应该使用它......

不要听它,它作为整个答案是绝对不正确的。阅读本文后,您应该做什么和不应该做什么更好地决定。虽然它主要是关于 Qt 线程的,但这篇文章也讲述了异步编程(并且,正如Emerald Weapon 所提到的,这正是 deleteLater() 的创建目的)。

此外,智能指针和 QObject 父所有权与使用deleteLater(). 这两种技术实际上都在使用简单的delete操作。正如文章所示,正如Emerald Weapon的回答所证明的那样:delete不能解决问题deleteLater()。所以如果你需要删除你使用的对象delete,如果你需要为你使用的删除安排它deleteLater()

顺便说一句,如果你想使用智能指针,deleteLater()你可以指定删除器:

// Shared Pointer
QSharedPointer<MyObject> obj = 
        QSharedPointer<MyObject>(new MyObject, &QObject::deleteLater);
// Scoped Pointer
QScopedPointer<MyObject, QScopedPointerDeleteLater> customPointer(new MyObject);
Run Code Online (Sandbox Code Playgroud)

最后,对于非子对象,在 , 的析构函数中使用不是错误。deleteLater()QObject