当前位置: 首页 > news >正文

Qt deleteLater 延迟删除原理

deleteLater 调用

事件发送

void QObject::deleteLater()
{QCoreApplication::postEvent(this, new QDeferredDeleteEvent());
}
  • 首先该对象继承QObject
  • 调用deleteLater, 内部会发送删除事件QCoreApplication::postEvent(this, new QDeferredDeleteEvent()) 到事件循环的队列中
  • 最终事件循环会调用 reciver->event(Qevent)

事件接收

bool QObject::event(QEvent *e)
{switch (e->type()) {case QEvent::Timer:timerEvent((QTimerEvent*)e);break;case QEvent::ChildAdded:case QEvent::ChildPolished:case QEvent::ChildRemoved:childEvent((QChildEvent*)e);break;case QEvent::DeferredDelete:qDeleteInEventHandler(this);break;...return true;
}void qDeleteInEventHandler(QObject *o)
{delete o;
}
  • event(QEvent *e) 通过事件类型判断,是否为延迟删除类型:QEvent::DeferredDelete
  • 如果是延迟删除类型,则会调用qDeleteInEventHandler

事件发送实现

设置删除事件的 looplevel 和 eventLevel

void QCoreApplication::postEvent(QObject *receiver, QEvent *event, int priority)
{Q_TRACE_SCOPE(QCoreApplication_postEvent, receiver, event, event->type());if (receiver == nullptr) {qWarning("QCoreApplication::postEvent: Unexpected null receiver");delete event;return;}auto locker = QCoreApplicationPrivate::lockThreadPostEventList(receiver);if (!locker.threadData) {// posting during destruction? just delete the event to prevent a leakdelete event;return;}QThreadData *data = locker.threadData;// if this is one of the compressible events, do compressionif (receiver->d_func()->postedEvents&& self && self->compressEvent(event, receiver, &data->postEventList)) {Q_TRACE(QCoreApplication_postEvent_event_compressed, receiver, event);return;}if (event->type() == QEvent::DeferredDelete)receiver->d_ptr->deleteLaterCalled = true;if (event->type() == QEvent::DeferredDelete && data == QThreadData::current()) {// remember the current running eventloop for DeferredDelete// events posted in the receiver's thread.// Events sent by non-Qt event handlers (such as glib) may not// have the scopeLevel set correctly. The scope level makes sure that// code like this://     foo->deleteLater();//     qApp->processEvents(); // without passing QEvent::DeferredDelete// will not cause "foo" to be deleted before returning to the event loop.// If the scope level is 0 while loopLevel != 0, we are called from a// non-conformant code path, and our best guess is that the scope level// should be 1. (Loop level 0 is special: it means that no event loops// are running.)int loopLevel = data->loopLevel;int scopeLevel = data->scopeLevel;if (scopeLevel == 0 && loopLevel != 0)scopeLevel = 1;static_cast<QDeferredDeleteEvent *>(event)->level = loopLevel + scopeLevel;}// delete the event on exceptions to protect against memory leaks till the event is// properly owned in the postEventListQScopedPointer<QEvent> eventDeleter(event);Q_TRACE(QCoreApplication_postEvent_event_posted, receiver, event, event->type());data->postEventList.addEvent(QPostEvent(receiver, event, priority));eventDeleter.take();event->posted = true;++receiver->d_func()->postedEvents;data->canWait = false;locker.unlock();QAbstractEventDispatcher* dispatcher = data->eventDispatcher.loadAcquire();if (dispatcher)dispatcher->wakeUp();
}

通过looplevel 和 eventLevel 判断 确认是是否执行延迟删除事件

 const bool allowDeferredDelete =(eventLevel > loopLevel|| (!eventLevel && loopLevel > 0)|| (event_type == QEvent::DeferredDelete&& eventLevel == loopLevel));if (!allowDeferredDelete) {// cannot send deferred deleteif (!event_type && !receiver) {// we must copy it first; we want to re-post the event// with the event pointer intact, but we can't delay// nulling the event ptr until after re-posting, as// addEvent may invalidate pe.QPostEvent pe_copy = pe;// null out the event so if sendPostedEvents recurses, it// will ignore this one, as it's been re-posted.const_cast<QPostEvent &>(pe).event = nullptr;// re-post the copied event so it isn't lostdata->postEventList.addEvent(pe_copy);}continue;}
  • 如果符合条件 调用 QCoreApplication::sendEvent(r, e);
  • 不符合条件 制空当前队列指针const_cast<QPostEvent &>(pe).event = nullptr;,将指针副本插入到队列尾部 continue 跳过``(完成一次延迟删除的机会)

最总调用event 事件:

bool QCoreApplicationPrivate::notify_helper(QObject *receiver, QEvent * event)
{// Note: when adjusting the tracepoints in here// consider adjusting QApplicationPrivate::notify_helper too.Q_TRACE(QCoreApplication_notify_entry, receiver, event, event->type());bool consumed = false;bool filtered = false;Q_TRACE_EXIT(QCoreApplication_notify_exit, consumed, filtered);// send to all application event filters (only does anything in the main thread)if (QCoreApplication::self&& receiver->d_func()->threadData.loadRelaxed()->thread.loadAcquire() == mainThread()&& QCoreApplication::self->d_func()->sendThroughApplicationEventFilters(receiver, event)) {filtered = true;return filtered;}// send to all receiver event filtersif (sendThroughObjectEventFilters(receiver, event)) {filtered = true;return filtered;}// deliver the eventconsumed = receiver->event(event);return consumed;
}

延迟删除的核心(个人理解)

  • 1: 就是通过记录looplevel 和 eventlevel 然后在条件比较两者
  • 2:eventLevel 是每个事件中的一个快照相当于curentlevel, 他记录的是当前looplevel, 而looplevel 是不断变换的。相当于looplevel 是一个动态的全局或者静态的变量, eventLevel 是每个事件中的一个属性

场景1:主循环中的延迟删除

// loopLevel = 0 (初始)
QCoreApplication::exec(); // loopLevel → 1QObject* obj = new QObject;
obj->deleteLater(); // eventLevel = 1// 事件处理时:
//   eventLevel=1, loopLevel=1 → 条件3满足 → 立即删除

场景2:嵌套循环中的跨级删除

// 主循环中 (loopLevel=1)
QObject* outerObj = new QObject;
outerObj->deleteLater(); // eventLevel=1QEventLoop nestedLoop; 
// 进入嵌套循环 (loopLevel=2)// 处理outerObj的延迟删除事件:
//   eventLevel=1, loopLevel=2
//   1 > 2? false
//   !1 && 2>0? false
//   事件非DeferredDelete → 不满足条件 → 跳过删除
http://www.dtcms.com/a/310216.html

相关文章:

  • 逻辑回归召回率优化方案
  • 第15讲——微分方程
  • 云服务器涉及的应用场景
  • 将本地commit已经push到orgin后如何操作
  • 应用Builder模式在C++中进行复杂对象构建
  • 梦幻接球 - 柔和色彩反弹小游戏
  • c#保留小数点后几位 和 保留有效数字
  • ctfshow_web签到题
  • LS-DYNA 分析任务耗时长,企业如何科学提升许可证使用效率?
  • 编程算法:驱动技术创新与业务增长
  • 丝杆支撑座在电子装配中的关键作用
  • 退出python的base环境
  • 基于STM32的数控机床物联网改造研究
  • 大模型应用
  • Flowable BPMN:智能流程自动化技术全面指南
  • Linux基础服务(DNS和DHCP)
  • 安卓开发--RelativeLayout(相对布局)
  • 数论:卢卡斯定理
  • 计算机网络:组播和多播有什么区别?
  • ESD监控系统确保工厂生产设备的静电安全
  • 机试备考笔记 1/31
  • 【科普】怎么理解Modbus、TCP、UDP
  • JavaWeb笔记2-JavaScriptVueAjax
  • MATLAB的三维重建系统
  • 从 0 到 1 认识 Spring MVC:核心思想与基本用法(上)
  • CIU32L030=CW32L010 PIN=PIN免费送样,开发板
  • 【论文学习】KAG论文翻译
  • 计算机基础速通--数据结构·线性表应用
  • RA4M2_MINI驱动OLED(1)----驱动OLED
  • LangChain框架入门04:10分钟优雅接入主流大模型