Qt 内存管理机制

Qt的内存管理机制 Qt提供了一套方便的机制帮助我们进行内存和资源管理,使我们从繁重的劳动中得到了部分的解放,但同时也要注意到那些很容易坑,这样才能写出健壮的正确执行的程序。如有错误之处,欢迎批评指正。 阅读详情

(注:本文为转载,非本人原创!原文地址:http://devbean.blog.51cto.com/448512/526734 )

这篇文章首先发布于我的主页http://www.devbean.info,以后也会直接发布在那里。现在有 Flex 4 的一篇和 《从 C++ 到 Objective-C》系列,感谢大家支持!

强类型语言在创建对象时总会显式或隐式地包含对象的类型信息。也就是说,强类型语言在分配对象内存空间时,总会关联上对象的类型。相比之下,弱类型 语言则不会这样做。在分配了内存空间之后,有两种方法释放空间:手工释放,或者是使用垃圾收集器。C++ 要求开发者手工释放内存空间。这样做的好处是,开发者对内存有完全的控制能力,知道什么时候释放比较合适。Java 则使用垃圾收集器。它在后台会有一个线程根据一定的算法不停地查看哪些对象已经不被使用,可以被回收。这样做则可以将开发者从底层实现中解放出来,只需关 注于业务逻辑。

本文关注于 Qt 的内存管理,这里会使用 Qt 的机制,来实现一个简单的垃圾回收器。

C++ 内存管理机制

C++ 要求开发者自己管理内存。有三种策略:

  1. 让创建的对象自己 delete 自己的子对象(这里所说的子对象,是指对象的属性,而不是子类,以下类似);
  2. 让最后一个对象处理 delete;
  3. 不管内存。

最后一种通常成为“内存泄漏”,被认为是一种 bug。所以,我们现在就是要选出前面两种哪一种更合适一些。有时候,delete 创建的对象要比 delete 它的所有子对象简单得多;有时候,找出最后一个对象也是相当困难的。

Qt 内存管理机制

Qt 在内部能够维护对象的层次结构。对于可视元素,这种层次结构就是子组件与父组件的关系;对于非可视元素,则是一个对象与另一个对象的从属关系。在 Qt 中,删除父对象会将其子对象一起删除。这有助于减少 90% 的内存问题,形成一种类似垃圾回收的机制。

QPointer

QPointer 是一个模板类。它很类似一个普通的指针,不同之处在于,QPointer 可以监视动态分配空间的对象,并且在对象被 delete 的时候及时更新。

 
  1. // QPointer 表现类似普通指针 
  2. QDate *mydate = new QDate(QDate::currentDate()); 
  3. QPointer mypointer = mydata; 
  4. mydate->year();    // -> 2005 
  5. mypointer->year(); // -> 2005 
  6.   
  7. // 当对象 delete 之后,QPointer 会有不同的表现 
  8. delete mydate; 
  9.   
  10. if(mydate == NULL) 
  11.     printf("clean pointer"); 
  12. else 
  13.     printf("dangling pointer"); 
  14. // 输出 dangling pointer 
  15.   
  16. if(mypointer.isNull()) 
  17.     printf("clean pointer"); 
  18. else 
  19.     printf("dangling pointer"); 
  20. // 输出 clean pointer 

注意上面的代码。一个原始指针 delete 之后,其值不会被设置为 NULL,因此会成为野指针。但是,QPionter 没有这个问题。

QObjectCleanupHandler

Qt 对象清理器是实现自动垃圾回收的很重要的一部分。它可以注册很多子对象,并在自己删除的时候自动删除所有子对象。同时,它也可以识别出是否有子对象被删 除,从而将其从它的子对象列表中删除。这个类可以用于不在同一层次中的类的清理操作,例如,当按钮按下时需要关闭很多窗口,由于窗口的 parent 属性不可能设置为别的窗口的 button,此时使用这个类就会相当方便。

 
  1. // 创建实例 
  2. QObjectCleanupHandler *cleaner = new QObjectCleanupHandler; 
  3. // 创建窗口 
  4. QPushButton *w = new QPushButton("Remove Me"); 
  5. w->show(); 
  6. // 注册第一个按钮 
  7. cleaner->add(w); 
  8. // 如果第一个按钮点击之后,删除自身 
  9. connect(w, SIGNAL(clicked()), w, SLOT(deleteLater())); 
  10. // 创建第二个按钮,注意,这个按钮没有任何动作 
  11. w = new QPushButton("Nothing"); 
  12. cleaner->add(w); 
  13. w->show(); 
  14. // 创建第三个按钮,删除所有 
  15. w = new QPushButton("Remove All"); 
  16. cleaner->add(w); 
  17. connect(w, SIGNAL(clicked()), cleaner, SLOT(deleteLater())); 
  18. w->show(); 

在上面的代码中,创建了三个仅有一个按钮的窗口。第一个按钮点击后,会删除掉自己(通过 deleteLater() 槽),此时,cleaner 会自动将其从自己的列表中清除。第三个按钮点击后会删除 cleaner,这样做会同时删除掉所有未关闭的窗口。

Qt 垃圾收集

随着对象变得越来越复杂,很多地方都要使用这个对象的时候,什么时候作 delete 操作很难决定。好在 Qt 对所有继承自 QObject 的类都有很好的垃圾收集机制。垃圾收集有很多种实现方法,最简单的是引用计数,还有一种是保存所有对象。下面我们将详细讲解这两种实现方法。

引用计数

应用计数是最简单的垃圾回收实现:每创建一个对象,计数器加 1,每删除一个则减 1。

 
  1. class CountedObject 
  2. { 
  3. public: 
  4.     CountedObject() 
  5.     { 
  6.         ctr=0; 
  7.     } 
  8.   
  9.     void attach() 
  10.     { 
  11.         ctr++; 
  12.     } 
  13.   
  14.     void detach() 
  15.     { 
  16.         ctr--; 
  17.         if(ctr <= 0) 
  18.             delete this; 
  19.     } 
  20. private: 
  21.     int ctr; 
  22. }; 

 

每一个子对象在创建之后都应该调用 attach() 函数,使计数器加 1,删除的时候则应该调用 detach() 更新计数器。不过,这个类很原始,没有使用 Qt 方便的机制。下面我们给出一个 Qt 版本的实现:

 
  1. class CountedObject : public QObject 
  2. { 
  3.     Q_OBJECT 
  4. public: 
  5.     CountedObject() 
  6.     { 
  7.         ctr=0; 
  8.     } 
  9.   
  10.     void attach(QObject *obj) 
  11.     { 
  12.         ctr++; 
  13.         connect(obj, SIGNAL(destroyed(QObject*)), SLOT(detach())); 
  14.     } 
  15.   
  16. public slots: 
  17.     void detach() 
  18.     { 
  19.         ctr--; 
  20.         if(ctr <= 0) 
  21.             delete this; 
  22.     } 
  23.   
  24. private: 
  25.     int ctr; 
  26. }; 

我们利用 Qt 的信号槽机制,在对象销毁的时候自动减少计数器的值。但是,我们的实现并不能防止对象创建的时候调用了两次 attach()。

记录所有者

更合适的实现是,不仅仅记住有几个对象持有引用,而且要记住是哪些对象。例如:

 
  1. class CountedObject : public QObject 
  2. { 
  3. public: 
  4.     CountedObject() 
  5.     { 
  6.     } 
  7.   
  8.     void attach(QObject *obj) 
  9.     { 
  10.         // 检查所有者 
  11.         if(obj == 0) 
  12.             return; 
  13.         // 检查是否已经添加过 
  14.         if(owners.contains(obj)) 
  15.             return; 
  16.         // 注册 
  17.         owners.append(obj); 
  18.         connect(obj, SIGNAL(destroyed(QObject*)), SLOT(detach(QObject*))); 
  19.     } 
  20.   
  21. public slots: 
  22.     void detach(QObject *obj) 
  23.     { 
  24.         // 删除 
  25.         owners.removeAll(obj); 
  26.         // 如果最后一个对象也被 delete,删除自身 
  27.         if(owners.size() == 0) 
  28.             delete this; 
  29.     } 
  30.   
  31. private: 
  32.     QList owners; 
  33. }; 

现在我们的实现已经可以做到防止一个对象多次调用 attach() 和 detach() 了。然而,还有一个问题是,我们不能保证对象一定会调用 attach() 函数进行注册。毕竟,这不是 C++ 内置机制。有一个解决方案是,重定义 new 运算符(这一实现同样很复杂,不过可以避免出现有对象不调用 attach() 注册的情况)。


本文来自 DevBean's World: http://www.devbean.info 。
转载时请标明文章原始出处:
http://www.devbean.info/2011/03/qt_memory_management/ 。
QT(二)QT常用类 内存管理机制 QObject的介绍 QWidget的介绍 QString的介绍 QT内存管理机制 内存管理的概念 QT对象树 阅读详情

相关推荐

Qt内存管理(一) 半自动内存管理机制

概述 看多了Qt的代码就会发现,很多人的代码里大量使用new,却很少看到delete,以至于我刚学Qt时也养成了这个习惯,在写C++时也不用delete,结果造成很多麻烦。 原因在于Qt采用半自动的内存管理,不像c++那种全需要自己delete堆内存对象。Qt对象继承自QObject, QObject内部有一个list,会保存children,即QObjectList* children;还有...

yao5hed的专栏 3792

【精华】详解Qt中的内存管理机制

前言 内存管理,是对软件中内存资源的分配与释放进行有效管理的方法和理论。 众所周知,内存管理是软件开发的一个重要的内容。软件规模越大,内存管理可能出现的问题越多。如果像C语言一样手动地管理内存,一会给开发人员带来巨大的负担,二是手动管理内存的可靠性较差。 Qt为软件开发人员提供了一套内存管理机制,用以替代手动内存管理。 下面开始逐条讲述Qt中的内存管理机制。 一脉相承的栈与堆的内存管理 了解C语言的同学都知道,C语言中的内存分配有两种形式:栈内存、堆内存。 栈内存 栈内存的管理是由编译器来做的,栈上申请的内

撬动未来的支点的专栏 7407

车辆TBOX科普 第7次 TBOX技术深度解析:硬件架构与核心组件详解

摘要: TBOX(车载远程信息处理单元)是智能网联汽车的核心组件,承担数据采集、通信连接与安全交互等关键功能。其硬件架构以主控单元为核心,采用ARM架构处理器(如NXP i.MX系列)实现高效能低功耗处理,搭配DDR4/LPDDR5内存保障性能,eMMC/UFS存储确保数据可靠性。设计中需平衡车规级可靠性(AEC-Q100)、EMC兼容性及成本控制,同时集成通信、定位与安全模块。未来趋势聚焦异构计算、先进制程及功能安全(ASIL-D)与信息安全融合,推动TBOX向边缘计算节点演进。该技术是汽车智能化转型的重

IT深耕十余载,大道之简 861

关于Qt的内存管理机制

关于Qt的内存管理机制的理解

wlqxyl的博客 1542

Android开发者必看:火山引擎API验签实战,5分钟搞定年龄变化接口调用

本文为Android开发者提供火山引擎API验签实战指南,重点解析HMAC-SHA256签名算法实现,并以年龄变化接口为例展示完整调用流程。通过OkHttp封装和性能优化建议,帮助开发者5分钟内快速集成火山引擎人像处理功能,解决API调用中的签名验证、参数编码等核心问题。

weixin_30342209的博客 317

SD - WAN:企业出海的网络加速器

例如,一家中国的跨境电商企业,在欧美市场的促销活动期间,借助 SD - WAN 技术,即使面对海量订单数据的交互,也能确保欧美客户在浏览商品、下单支付时感受到近乎本地网络的流畅体验,大大提升了客户满意度,稳住了销售增速。企业无需在海外本地部署大量冗余服务器,只需依托云台,借助 SD - WAN 快速稳定的网络连接,即可轻松实现业务拓展,进一步精简运营架构,提升整体效能。在未来,随着技术的不断演进和企业出海需求的持续增长,SD - WAN 将持续赋能,助力更多企业在全球市场扬帆远航,书写辉煌篇章。

idcicp_com的博客 446

【QT入门】 Qt内存管理机制详解

【QT入门】 Qt内存管理机制详解

LF__plus的博客 2389

基于Stigmergy的团队LLM wiki协作机制与FastAPI工程实践

大语言模型驱动的知识管理正在改变个人笔记与团队文档的维护方式,但当多人共同维护一个维基时,如何避免版本覆盖、上下文丢失和幻觉污染成为核心挑战。Stigmergy这一源自生物学的协作机制提供了新思路:通过共享环境中的痕迹(如评论、标记、修订历史)实现异步协作,无需实时沟通或中心协调者。本文将原理落地为可工程化的系统,设计Page、Revision、Trace三大实体,并结合向量索引与LLM审查流程,最终用FastAPI与SQLite搭建一个最小可运行原型。从白蚁筑巢到团队知识库,Stigmergy让每个参与者

weixin_34174322的博客 364

Qt开发:Qt的内存管理机制

Qt提供了一套完善的内存管理机制,主要基于父子对象关系和智能指针等方式,开发者只需正确建立父子关系,无需担心子对象的内存泄漏问题。

倔强老吕的博客 1484

Classic AUTOSAR精讲专栏目录

欢迎大家来到钢琴上的汽车软件创建的《Classic AUTOSAR精讲系列专栏》,期待在这里能够与大家一起进步,分享成功,分享喜悦!下面蓝色的文章标题都是传送门,点击直接跳转到对应文章。

酒无忧的博客 3905

【AUTOSAR AP PHM 】PHM 标准化“检查点上报接口”落地指南(AUTOSAR AP · R24-11取向)

本文介绍了AUTOSAR AP R24-11标准下PHM(平台健康管理)模块中"检查点上报接口"的标准化实现方案。主要内容包括: 核心设计理念:采用"配置优先"原则,通过部署模型预先定义监管参数,应用进程只需简单上报枚举标识,具体判定由PHM执行。 职责划分: 应用进程:仅调用ReportCheckpoint接口上报枚举值 PHM:负责Alive计数、Deadline区间判定和Logical路径校验 EM/IdsM:提供进程状态和越权检测 三类监管机制: Alive:

探索C++编程的奥秘,分享深入的技术见解和实践,旨在激发读者创造力与解决问题的思维。 220

C++ 与 Qt 的内存管理机制

C++ 需要程序员手动。

u013576331的博客 1472

[SaaS] 阿里妈妈-万相营造

有controlnet的介入,我们是默认controlnet会介入,在inapinting时会把带有商品的画布做一点扩充,然后走inapinting和controlnet,其实也做了一点outpainting的工作。基于阿里妈妈营销平台,提供从图文到视频再到落地页的素材级智能化创意支持,是您营销创意数字资产累积和升值的阵地,最大化提升营销的效率和效果。目前看来抠图基本都是sam了,现在weshop也是,都有一个预扣好的主体,但是一点进去也会重新sam。atomovideo->图生视频。

liguandong 524

Qt 的内存管理机制

那么下面我们就写一个代码,我们自己写一个类,这个类继承自 QLabel,当然继承其他的可以挂到对象树上的类也是可以的,因为 QLabel 可以显示出来,所以我们创建一个类继承自 QLabel,然后我们重写这个类的析构函数,我们在这个类的析构函数里面添加一个打印语句,这样我们就可以在释放的时候看到是否释放了。其实就是当我们关闭界面的时候,因为关闭界面了,说明我们已经不需要这个界面里面的控件显示了,所以我们理所当然的是可以将该控件释放掉的。此时我们看到的可能就是这样,那么此时的对象树是什么样子的呢?

m0_73455775的博客 1709

【Altium designer】如何添加过孔阵列

按下图1指示,执行【Tool】菜单栏下【Via Stitching/Shielding】选项卡中的【Add Stitching to Net...】选项 图1 “添加过孔阵列”选项 点击【Add Stitching to Net...】选项后,会跳出一个窗口,让我们设置过孔阵列的参数信息,如下图2所示。 图2 过孔阵列参数设置 过孔阵列区域:勾选该选项框,即可绘制多边形区域; 过孔内径与焊盘直径:比如内径 【Hole Size】设为12mil,焊盘直径【Diameter】设为24mil; .

夜半少年的博客 2万+

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

Qt中的内存管理机制

值得一提的是,之所以Qt中具有各种各样的内存管理方式,是因为它能够减轻开发者的负担,更加专注于业务代码的实现,而不是被内存问题折腾的焦头烂额。堆内存是另外一种管理方式。QPointer是防止悬挂指针(即野指针)的有效手段,因为所指对象一旦被删除,QPointer会自动置空,在使用时,判断指针是否为空即可,不为空说明对象可以使用,不会产生内存访问错误的问题。们知道Qt是C++的框架,C++是对C语言的扩展,所以C语言中的内存管理方式(堆、栈)和动态内存管理(堆内存释放问题)存在的问题,在C++中仍然存在。

u010787096的博客 598

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

总结Qt中三大机制(二):内存管理机制

这篇文章继续来总结关于内存管理的内容。 2.内存管理机制 我们知道C++中并没有什么内存管理机制。对于栈上对象我们无需关心,因为它的空间由系统负责,而堆上对象必须由程序猿负责空间的申请与释放。Qt作为第三方类库,给出了一套很好的内存管理机制。 首先需要明确一个概念,Qt作为一套GUI(图形用户界面)类库,在开发时,我们应用最多的就是各类窗口,其中经常用到父子窗口。必须明确,父子窗口一种窗口之...

Eason_Grace的博客 3275

华为的C语言编程规范.pdf

华为技术有限公司内部技术规范。本规范制定了编写C语言程序的基本原则、规则和建议。从代码的清晰、简洁、可测试、安全、程序效率、可移植各个方面对C语言编程作出了具体指导。

Qt内存管理机制

强类型语言在创建对象时总会显式或隐式地包含对象的类型信息。也就是说,强类型语言在分配对象内存空间时,总会关联上对象的类型。相比之下,弱类型 语言则不会这样做。在分配了内存空间之后,有两种方法释放空间:手工释放,或者是使用垃圾收集器。C++ 要求开发者手工释放内存空间。这样做的好处是,开发者对内存有完全的控制能力,知道什么时候释放比较合适。Java 则使用垃圾收集器。它在后台会有一个线程根据一定的算

一起摇摆_xianggy的专栏 934
上一篇: 对数极坐标
下一篇: Lab颜色空间
ChenLee_1
博客等级 码龄17年 6199粉丝 179原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值