假设我有以下代码段,在qto的析构函数中调用deleteLater是否可以安全地管理它可能管理的其他QT对象?
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MyQTObject qto;
qto.show();
return a.exec();
}
因为我已使用检漏器分析了类似的相似代码以及调用了deleteLater的所有对象,所以除非我用正常删除替换了呼叫,否则无法正确解除分配。 如果我已正确理解这一点,则deleteLater仅在QT消息队列中注册删除事件。这可能是在主要范围结束时调用qto的析构函数的问题,而QT消息循环已经从a.exec的返回结束了吗?因此,永远不会处理删除事件,实际上甚至没有被推入消息队列,因为没有?
答案 0 :(得分:12)
这篇文章相当陈旧,但我希望在我自己提出这个问题时添加一些我希望遇到的答案。
gallery_media
与异步操作结合使用非常有用。我认为,它最近可能会将信号连接到lambda函数。
假设您有一些deleteLater()
要异步执行(在多线程意义上,就事件循环中的调度执行而言)。你可以这样做:
longComputation()
其中void MyClass::deferLongComputation()
{
QTimer* timer = new QTimer();
connect(timer,
&QTimer::timeout,
[this, timer](){this->longComputiation(); timer->deleteLater();});
timer->setSingleShot(true);
timer->start();
}
负责在{1}}执行其职责后安全处置deleteLater()
,并避免人们原本会发生的内存泄漏。
使用QTimer
多线程可以使用相同的模式。
答案 1 :(得分:8)
据我了解,当您需要在插槽调用中删除对象时,最常使用deleteLater。如果在这种情况下使用delete并且从插槽返回时引用了对象,则会发生对未初始化内存的引用。
因此,deleteLater通过在事件循环上放置一条消息来请求删除该对象,该消息在某个时刻处理,从插槽返回时可以安全删除。
我希望在析构函数中使用deleteLater意味着对象可能超出范围,在其托管对象上调用deleteLater,但在事件循环有机会删除对象之前退出,如退出来自QApplication :: exec()将终止事件循环。
答案 2 :(得分:3)
这个问题已经过时了,但是我会把它留给下一代) 标记为答案的答复是正确的,但却很奇怪。 实际上你的问题包含一个正确的答案:
消息循环已经从a.exec返回结束?就这样 删除事件永远不会被处理,实际上甚至没有被推入 消息队列,因为没有。
这正是发生的事情。 deleteLater()
所做的只是将删除事件发布到outter事件循环中。当事件被处理时 - 对象被删除。但是如果没有outter事件循环并且在执行流程中稍后没有遇到事件循环 - 事件将永远不会被发布,因此永远不会删除对象。
如果在对象的析构函数中调用deleteLater()
并将对象放在堆栈上 - 当对象超出范围时调用deleteLater()
。在您的示例中,当遇到main()
函数的右括号时,会发生“超出范围”。但是,到那时,a.exec()
(代表Qt App的主要事件循环)已经返回 - > 没有事件循环 - > 强调> deleteLater()
被调用,但无法发布删除事件 - > 对象应该是“deletedLater”永远不会被删除...
关于“何时使用deleteLater()”部分:
Kuba Ober 回答:
一般来说,存在一系列狭隘的情况 应该使用deleteLater。很可能你根本就不应该使用 它...
不要听,整个答案绝对不正确。在阅读this article之后,你应该做些什么以及不应该做什么。虽然,它主要是关于Qt线程,但文章还讲述了ascynchronous编程(并且,正如 Emerald Weapon 所提到的,它正是为其创建的deleteLater())。
此外,智能指针和QObject父级所有权与使用deleteLater()
的删除计划无关。这两种技术实际上都是在引擎盖下使用简单的delete
操作。正如文章所示,并且翡翠武器的答案证明:delete
无法解决问题deleteLater()
。因此,如果您需要删除使用delete
的对象,如果您需要安排删除对象,请使用deleteLater()
。
顺便说一句,如果你想使用deleteLater()
智能指针,你可以指定删除器:
// Shared Pointer
QSharedPointer<MyObject> obj =
QSharedPointer<MyObject>(new MyObject, &QObject::deleteLater);
// Scoped Pointer
QScopedPointer<MyObject, QScopedPointerDeleteLater> customPointer(new MyObject);
最后,对于非子对象,在deleteLater()
的析构函数中使用QObject
是一个 NOT 错误。
答案 3 :(得分:1)
您是正确的deleteLater()
命令仅由事件循环执行。
来自QObject
的{{3}}:
安排此对象删除。
当控件返回事件时,对象将被删除 环。如果此函数是事件循环未运行 调用(例如,之前在对象上调用deleteLater() QCoreApplication :: exec()),该对象将被删除一次 事件循环开始。如果在主事件循环之后调用deleteLater() 已停止,该对象将不会被删除。 从Qt 4.8开始,如果在一个居住在的对象上调用deleteLater() 线程没有运行事件循环,当对象被销毁时 线程完成。
注意进入和离开新事件循环(例如,通过打开模态 对话框)将不执行延迟删除;对于对象 删除后,控件必须返回事件循环 deleteLater()被调用。
注意:多次调用此函数是安全的;当。。。的时候 第一个延期删除事件已发送,任何待处理事件 对象将从事件队列中删除。
如果您希望在删除QObjects
时删除所有子qto
,请确保将qto
作为父级创建。
答案 4 :(得分:1)
一般来说,应该使用deleteLater的一小部分情况。很可能你根本就不应该使用它。
对于非子对象,在QObject的析构函数中使用它是错误的。正如您所发现的,如果没有事件循环,QObject可能会被破坏。例如,在deleteLater
Qt模块的对象析构函数中没有qtbase
个调用。
这里必须要小心:例如,~QTcpServer()
调用close()
调用d->socketEngine->deleteLater()
,但套接字引擎已经是服务器的子代,将被{{1删除无论如何。
据我所知,~QObject()
应该执行以下操作之一:
MyQTObject
或QScopedPointer
,