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.pswp.cn/news/917266.shtml
繁体地址,请注明出处:http://hk.pswp.cn/news/917266.shtml
英文地址,请注明出处:http://en.pswp.cn/news/917266.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

TypeScript SDK 升级:通过 Upload Relay 赋能更多应用

自 3 月主网上线以来&#xff0c;Walrus 开发者社区持续展现出强劲的发展势头&#xff1a; 当前 Walrus 已存储超 758 TB 数据&#xff0c;为数百个项目提供支持。在 2025 年 6 月举办的 Sui Overflow 黑客松上&#xff0c;Walrus 成为最受欢迎的数据层。该赛事共收到 599 个项…

C#线程同步(二)锁

目录 1.lock 2.Monitor 3.锁的其它要注意的问题 3.1同步对象的选择 3.2什么时候该上锁 3.3锁和原子性 3.4嵌套锁 3.5 死锁 3.6 性能 4.Mutex 5.Semaphore 1.lock 让我们先看一段代码&#xff1a; class ThreadUnsafe {static int _val1 1, _val2 1;static void G…

鸿蒙智能居家养老系统构思(续二)—— 适老化烹饪中心详细构思

一、背景在“写给华为鸿蒙智家 —— 智能居家养老系统构思”一文中&#xff0c;结合对居家养老的理解及个人体验&#xff0c;提出了基于鸿蒙OS实现居家养老系统的粗略构思。其中包含“吃得好”。当老人到了不能随性外出活动、只能在家消耗时光时&#xff0c;除了一些看看电视、…

高斯透镜公式(调整镜头与感光元件之间的距离时,使得不同距离的物体在感光元件上形成清晰的影像)

当使用定焦镜头时&#xff0c;仍然可以调整镜头与感光元件&#xff08;或胶片&#xff09;之间的距离时&#xff0c;使得不同距离的物体在感光元件上形成清晰的影像。对此可以用高斯透镜公式进行解释&#xff1a; 一、透镜成像的基本原理 在光学中&#xff0c;一个基本的公式是…

预过滤环境光贴图制作教程:第三阶段 - GGX 分布预过滤

核心目标 GGX 分布是 PBR 中模拟粗糙表面高光反射的主流模型,其核心是通过统计分布描述微表面的朝向概率。本阶段的目标是: 基于第一阶段生成的环境图集,预计算 6 个级别的 GGX 过滤结果(对应不同粗糙度); 使用蒙特卡洛采样(Monte Carlo Sampling)加速 GGX 卷积计算;…

Spring框架与AutoCAD结合应用

什么是AutoCAD? AutoCAD简介 AutoCAD是由美国Autodesk公司开发的计算机辅助设计(CAD)软件,广泛应用于建筑、工程、制造、产品设计等领域。它支持2D绘图和3D建模,提供精确的图形工具和自动化功能,帮助用户高效创建技术图纸和模型。 主要功能 2D绘图:提供直线、圆弧、多…

Java 学习笔记:常用类、String 与日期时间处理

作为一名名 Java 初学者&#xff0c;最近在学习过程中整理了一些关于常用类、String 类以及日期时间处理的知识点。这些内容是 Java 基础中的重点&#xff0c;也是日常编程练习中频繁用到的工具&#xff0c;掌握它们能让我们在写代码时更加得心应手。今天把这些笔记分享出来&am…

Android常用的adb和logcat命令

ADB ADB&#xff0c;即 Android Debug Bridge 是一种允许模拟器或已连接的 Android 设备进行通信的命令行工具&#xff0c;它可为各种设备操作提供便利&#xff0c;如安装和调试应用&#xff0c;并提供对 Unix shell&#xff08;可用来在模拟器或连接的设备上运行各种命令&…

重学JS-001 --- JavaScript算法与数据结构(一)JavaScript 基础知识

文章目录 变量 变量命名规则 变量命名 let vs const 变量使用范围 赋值 = 控制台输出 运算符 ++ -- == === !== 注释 转义字符 数据类型 7种 原始数据类型 1. string​​ 2. number​​ 3. ​​boolean​​ 4. null​​ 5. undefined​​ 6. ​​symbol​​(ES6 新增) 7. big…

MySQL数据闪回工具my2sql的使用

场景&#xff1a; 当你或者其它人员误操作数据库不小心删除或者更新了一批数据&#xff0c;但是是当时又没事先备份时&#xff0c;你可以 用这个 my2sql工具快速帮你找回数据。就是如此的丝滑。但是要注意的是只限于dml语句&#xff0c;所以我们在操作数据库前必需先备份哦&…

9.1无法恢复的错误与 panic!

无法恢复的错误与 panic! 有时你的代码中会发生严重问题&#xff0c;而你无能为力。在这些情况下&#xff0c;Rust 提供了 panic! 宏。实际上&#xff0c;有两种方式会导致 panic&#xff1a;一种是执行某个操作使代码产生 panic&#xff08;例如访问数组越界&#xff09;&…

分享低功耗单火线开关语音识别方案

在众多老旧建筑和常规家居环境里&#xff0c;单火线布线是主流方式。单火线语音识别芯片方案通过研发和应用特殊的单火线语音识别芯片&#xff0c;实现设备在单火线供电条件下稳定运行&#xff0c;并精准识别语音指令&#xff0c;为智能家居、智能照明等领域带来便捷的语音控制…

如何在Windows操作系统上通过conda 安装 MDAnalysis

MDAnalysis 是一个开源的 Python 库,旨在提供一个高效且灵活的方式来分析和处理分子动力学(MD)模拟数据。它可以从不同的文件格式中读取模拟轨迹和结构数据,进行复杂的数据处理和分析,广泛应用于生物物理学、化学、材料科学等领域。 一、创建虚拟环境 为了能够顺利安装,减…

实用PDF演示解决方案

它打破了传统阅 读模式&#xff0c;让PDF文档也能像PPT一样流畅播放&#xff0c;特别适合汇报、讲解等展示场景。它是绿色单文件版&#xff0c;无需安装&#xff0c;双击红色图标即点即用。运行后第一件事&#xff0c;建议把界面语言切换成中文&#xff0c;操作更顺手。导入PDF…

VS Code中如何关闭Github Copilot

点击顶部搜索栏后面的Copilot图标&#xff0c;在下拉菜单中选择Hide Copilot。在弹出的提示框中&#xff0c;点击Hide Copilot按钮就可以了。

MySQL学习从零开始--第六部分

Binlog是什么&#xff1f;有哪几种格式&#xff1f;推荐使用哪种&#xff0c;为什么 Binlog是什么 Binlog二进制日志是MySQL Server层记录所有更改数据库内容的操作日志的二进制文件&#xff0c;如操作UPDATE,DELETE,INSERTBinlog不记录SELECT&#xff0c;SHOW等查询操作使主从…

走进computed,了解computed的前世今生

computed&#xff08;计算属性&#xff09;并不是vue独创的&#xff0c;而是源自计算机科学和响应式编程的长期发展 计算理论的奠基&#xff1a; 函数式编程的纯函数思想&#xff1a;计算属性的核心特征&#xff08;无副作用、依赖输入确定输出&#xff09;直接来源于函数式编程…

Java 23 新特性解析与代码示例

Java 23 新特性解析与代码示例 文章目录Java 23 新特性解析与代码示例1. 引言2. 正式特性2.1. Markdown文档注释 (JEP 467)2.2. 废弃sun.misc.Unsafe的内存访问方法以移除 (JEP 471)2.3. ZGC&#xff1a;默认启用代际模式 (JEP 474)3. 预览特性3.1. 原始类型在模式、instanceof…

spring boot + mybatis + mysql 只有一个实体类的demo

使用MyBatis进行数据库操作&#xff0c;配置简单。主要演示了mybatis可以不用只使用方法名来对应mapper.java和mapper.xml。 目录结构 pom.xml src/ ├── main/ │ ├── java/ │ │ └── com/ │ │ └── springbootjdbcweb/ │ │ └── …

iRemovalPro完美绕iCloud插卡打电话,A12+支持iOS 18.1.1

iRemovalPro 专业工具全解析与操作指南 &#xff08;支持iOS 14.0 - 16.6.1&#xff0c;A7-A15芯片设备&#xff09; &#x1f449;下载地址见文末 iRemoval Pro iRemoval 专业版是一款来自外国安全研究员的工具&#xff0c;用来帮助一些人因为忘记自己的ID或者密码&#xff0c…