Qt 以后何时使用delete

Qt 以后何时使用delete,qt,message-queue,Qt,Message Queue,假设我有以下代码段,那么稍后在qto的析构函数中为它可能管理的其他QT对象调用Delete安全吗 int main(int argc, char *argv[]) { QApplication a(argc, argv); MyQTObject qto; qto.show(); return a.exec(); } 因为我用泄漏检测器分析了类似的代码,并且调用deleteLater的所有对象都没有正确释放,除非我用普通的delete替换调用。 如果我理解正确,

假设我有以下代码段,那么稍后在qto的析构函数中为它可能管理的其他QT对象调用Delete安全吗

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

    MyQTObject qto;
    qto.show();
    return a.exec();
}
因为我用泄漏检测器分析了类似的代码,并且调用deleteLater的所有对象都没有正确释放,除非我用普通的delete替换调用。
如果我理解正确,deleteLater只在QT消息队列中注册删除事件。这可能是在main的作用域末尾调用qto的析构函数,而QT消息循环已经以a.exec的返回结束的问题吗?因此,删除事件将永远不会被处理,事实上甚至不会被推送到消息队列中,因为没有消息队列?

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

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


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

您认为
deleteLater()是正确的
命令仅由事件循环执行

从for
QObject

计划删除此对象

当控件返回到事件时,对象将被删除 环如果启用此函数时事件循环未运行 调用(例如,在之前对对象调用deleteLater() QCoreApplication::exec()),一旦 事件循环已启动。如果在主事件循环之后调用deleteLater() 已停止,将不会删除该对象。 自Qt 4.8以来,如果对位于 没有运行事件循环的线程,当 线程完成

请注意,进入和离开新的事件循环(例如,通过打开模式 对话框)将不会执行延迟删除;对于要删除的对象 已删除,则控件必须返回到从中删除的事件循环 调用了deleteLater()

注意:多次调用此函数是安全的;当 传递第一个延迟删除事件,即 对象从事件队列中删除


如果要在删除
qto
时删除所有子
qo对象
,请确保它们是以
qto
作为父对象创建的。

一般来说,应该使用deleteLater的情况比较少。很可能你根本不应该使用它

对于非子对象,在QObject的析构函数中使用它是错误的。正如您所发现的,QObject很可能在不存在事件循环的情况下被破坏。例如,
qtbase
Qt模块中的对象析构函数中没有
deleteLater
调用

这里必须小心:例如,
~qtcserver()
调用
close()
调用
d->socketEngine->deleteLater()
,但是套接字引擎已经是服务器的子引擎,无论如何都会被
~QObject()
删除

据我所知,
MyQTObject
应该执行以下操作之一:

  • 使用智能指针,如
    QScopedPointer
    std::unique\u ptr
  • 将对象作为常规(非指针)成员
  • 使用原始指针并使对象成为其子对象

这篇文章有点过时了,但我想补充一点,那就是当我自己问这个问题时,我希望得到的答案

deleteLater()
与异步操作结合使用非常有用。我认为,随着最近将信号连接到lambda函数的可能性的增加,它尤其引人注目

假设您有一些要异步执行的
longcompulation()
(不是多线程,而是在事件循环中调度执行)。您可以这样做:

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

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

    timer->setSingleShot(true);
    timer->start();
}
其中
deleteLater()
负责在执行任务后安全地处理
QTimer
,并避免否则可能发生的内存泄漏


同样的模式也可以在多线程中使用
QFutureWatcher

这个问题已经很老了,但我将把它留给下一代) 被标记为答案的回答是正确的,但措辞奇怪。 实际上,你的问题包含了一个正确的答案:

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

这正是正在发生的事情。
deleteLater()
所做的一切只是将删除事件发布到outter事件循环中。当事件被处理时-对象被删除。但若并没有outter事件循环,并且在执行流的后面并没有遇到事件循环,那个么事件将永远不会被发布,所以对象永远不会被删除

如果在对象的析构函数中调用
deleteLater()
,并将对象放在堆栈上-
deleteLater()
将在对象超出范围时调用。在您的示例中,当遇到
main()
函数的右大括号时,会发生“超出范围”的情况。然而,到那时,
a.exec()
(代表Qt应用程序的主事件循环)已经返回了-->不再调用任何事件循环-->
deleteLater()
,但是没有地方发布删除事件<
// Shared Pointer
QSharedPointer<MyObject> obj = 
        QSharedPointer<MyObject>(new MyObject, &QObject::deleteLater);
// Scoped Pointer
QScopedPointer<MyObject, QScopedPointerDeleteLater> customPointer(new MyObject);