Qt deletelater函数分析(2)
夫唯不争,故天下莫能与之争 -- 老子
在C++中,delete 和 new 必须 配对使用,Qt作为C++的库,显然是不会违背C++原则。但是,qt有自己的内存管理,有时候虽然使用了new,却可以不用使用delete。
Qt半自动的内存管理:
在Qt中,以下情况下你new出的对象你可以不用亲自去delete:
1) QObject及其派生类的对象,如果其parent非0,那么其parent析构时会析构该对象。
2) 有些类的对象可以接收设置一些特别的标记,比如:
QWidget及其派生类的对象,可以设置 Qt::WA_DeleteOnClose 标志位(当close时会析构该对象)
QAbstractAnimation派生类的对象,可以设置 QAbstractAnimation::DeleteWhenStopped
QRunnable::setAutoDelete()
MediaSource::setAutoDelete()
...
---------------------------------------------------------------------------------------------------------------
在Qt中,最基础和核心的类是:QObject 。这里只关注两点:
父子关系 和deleteLater
1)父子关系
在Qt中,每个 QObject 内部都有一个list,用来保存所有的 children,还有一个指针,保存自己的parent。当它自己析构时,它会将自己从parent的列表中删除,并且析构掉所有的children。
注意: 这里讲的paent,child与c++的语法无关。这里:如果你在qml文件中写了一个Rectangle,在其内部又加了一个Text,则Text的parent是Rectangle。
建立与解除
创建一个QObject对象时,如果指定了父对象,它就会将自己添加到父对象的 children 列表中:

当一个QObject对象析构时,它会将自己从父对象的 children 列表中移除(parent非0的话):
官方还是建议通过deletelater来进行删除Qobject对象。

void QObject::setParent ( QObject * parent )
通过该函数,将自己从原父对象的children中删除,添加到新parent的children列表中:

获取父对象:QObject * QObject::parent () const

获取子对象,子对象可以有多个:const QObjectList & QObject::children () const

也可以通过findChild来查找某个child。
2)deleteLater
可以下载qt源码,看该函数的实现,我下载了qt5.11的源码:qt-everywhere-src-5.11.1, http://download.qt.io/official_releases/qt/5.11/5.11.1/single/
Qojbect.cpp(文件位置:qt-everywhere-src-5.11.1\qt-everywhere-src-5.11.1\qtbase\src\corelib\kernel )中对该函数的定义:
void QObject::deleteLater()
{
QCoreApplication::postEvent(this, new QDeferredDeleteEvent());
}
该函数的作用就是发出一个事件,请求自己被干掉。
事件循环稍后收到该事件,会将其派发给这个请求的发出者,然后,事件发出者调用delete将自己干掉:
bool QObject::event(QEvent *e)
{
switch (e->type()) {
...
case QEvent::DeferredDelete:
qDeleteInEventHandler(this);
break;
…
}
void qDeleteInEventHandler(QObject *o)
{
delete o;
}
例子1:
#include <QApplication>
#include <QLabel>
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QLabel *label = new QLabel("Hello Qt!");
label->show();
return app.exec();
}
这是 C++ GUI Programming with Qt 4 一书的第一个例子。我们注意到这儿的 label 既没有指定parent,也没有对其调用delete。所以,这儿会造成内存泄露。
三种改进方式
1)分配对象到stack而不是heap中
QLabel label("Hello Qt!");
label.show();
2)动手调用delete
int ret = app.exec();
delete label;
return ret;
3)设置标志位,这样,当我们点击关闭按钮时,close()函数将会调用deleteLater
label->setAttribute(Qt::WA_DeleteOnClose);
例子2
#include <QApplication>
#include <QLabel>
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QLabel label("Hello Qt!");
label.show();
label.setAttribute(Qt::WA_DeleteOnClose);
return app.exec();
}
运行正常,退出时会崩溃 ,因为label被close时,将会 delete 这儿label对象,但label对象却不是通过new分配到heap中的。
为了使得用户减少自己显式使用delete,Qt将delete隐藏的比较深。这样一来,不使用new为对象分配空间时,反倒需要多多小心了。
例子3:这个程序退出时会直接崩溃 。
#include <QtGui>
int main(int argc, char* argv[])
{
QApplication app(argc, argv);
QLabel label(tr"Hello Qt!");
QWidget w;
label.setParent(&w);
w.show();
return app.exec();
}
因为退出时,w 比 label 先被析构,当 w 被析构时,会删除chilren列表中的对象,也就是这儿的 label。但 label 却不是通过new分配在heap中,而是在stack中,delte stack中的东西会导致崩溃。
两种改进办法:
1)将label分配到heap中
QLabel *label = new QLabel("Hello Qt!");
label.setParent(&w)
2)确保label先于其parent被析构(调整一下顺序),这样,label析构时将自己从父对象的列表中移除自己,w析构时,children列表中就不会有分配在stack中的对象了。
QWidget w;
QLabel label(tr"Hello Qt!");
Qt 对象的父子关系的引入,简化了我们对内存的管理,但是,由于它会在你不太注意的地方调用 delete,所以,需要万分注意。
参考:
https://blog.csdn.net/dbzhang800/article/details/6300025
http://doc.qt.nokia.com/4.7/qobject.html
http://www.cuteqt.com/blog/?p=824
Qt deletelater函数分析(2)的更多相关文章
- Qt deletelater函数分析(1)
生活的全部意义在于无穷地探索尚未知道的东西,在于不断地增加更多的知识.--左拉 该函数是QObject类的函数: ---- ...
- Qt源码分析之QObject
原文:http://blog.csdn.net/oowgsoo/article/details/1529284 我感觉oowgsoo兄弟写的分析相当透彻,赞! 1.试验代码: #include < ...
- QT源码分析(从QApplication开始)
QT源码分析 转载自:http://no001.blog.51cto.com/1142339/282130 今天,在给同学讲东西的时候,谈到了Qt源代码的问题,才发现自己对Qt机制的了解是在太少了,而 ...
- 31.QPainter-rotate()函数分析-文字旋转不倾斜,图片旋转实现等待
在上章和上上上章: 28.QT-QPainter介绍 30.QT-渐变之QLinearGradient. QConicalGradient.QRadialGradient 学习了QPainter基础绘 ...
- split(),preg_split()与explode()函数分析与介
split(),preg_split()与explode()函数分析与介 发布时间:2013-06-01 18:32:45 来源:尔玉毕业设计 评论:0 点击:965 split()函数可以实 ...
- string函数分析
string函数分析string函数包含在string.c文件中,经常被C文件使用.1. strcpy函数原型: char* strcpy(char* str1,char* str2);函数功能: 把 ...
- start_amboot()函数分析
一.整体流程 start_amboot()函数是执行完start.S汇编文件后第一个C语言函数,完成的功能自然还是初始化的工作 . 1.全局变量指针r8设定,以及全局变量区清零 2.执行一些类初始化函 ...
- uboot的jumptable_init函数分析
一.函数说明 函数功能:安装系统函数指针 函数位置:common/exports.c 二.函数分析 void jumptable_init (void) { int i; gd->jt = (v ...
- Linux-0.11内核源代码分析系列:内存管理get_free_page()函数分析
Linux-0.11内存管理模块是源码中比較难以理解的部分,如今把笔者个人的理解发表 先发Linux-0.11内核内存管理get_free_page()函数分析 有时间再写其它函数或者文件的:) /* ...
随机推荐
- Flume架构以及应用介绍(转)
在具体介绍本文内容之前,先给大家看一下Hadoop业务的整体开发流程: 从Hadoop的业务开发流程图中可以看出,在大数据的业务处理过程中,对于数据的采集是十分重要的一步,也是不可避免的一步,从而引出 ...
- 按位与(&),或(|),异或(^),取反(~),左移(<<),右移(>>)
C语言提供的位运算符列表:运算符 含义 描述& 按位与 如果两个相应的二进制位都为1,则该位的结果值为1,否则为0| 按位或 两个相应的二进制位中只要有一个为1,该位的结果值为1^ 按位异或 ...
- 字符串翻转(C++)
1.字符串原地翻转,"abc"->"cba": int str_reverse(string &str,int first,int last) { ...
- OI歌曲汇总
在学习的间隙,我们广大的OIer创作了许多广为人知的歌曲 这里来个总结 (持续更新ing......) Lemon OI 葛平 Lemon OI chen_zhe Lemon OI kkksc03 膜 ...
- c语言博客作业03--循环结构
0.展示PTA总分 1.本章学习总结 1.1学习内容总结 循环语句 for语句: for( 表达式1; 表达式2; 表达式3 ) { // 需要执行的语句; } 其执行过程是:表达式 1 首先执行且只 ...
- leetcode题目讲解(Python):字符串转整数 (atoi)
分析这道题,输入数据有如下几种情况: 第一类:输入字符串无法转换为整数 这一类包含以下几种情况: 输入字符串为空 开头字符为数字.符号(+,-).空格以外的字符 有多个加减符号的字符串 符号没有紧跟数 ...
- [学习笔记] kd-tree
本文参考这位dalao的题解 前置技能:二叉查找树 其实kd-tree很简单的啦 和BST都差不多的啦 就是在划分的时候把每一维都比较一下就行啦 (\(dalao\)的kd-tree教程) 然而本蒟蒻 ...
- 2019_软工实践_Beta(2/5)
队名:955 组长博客:点这里! 作业博客:点这里! 组员情况 组员1(组长):庄锡荣 过去两天完成了哪些任务 文字/口头描述 ?按照时间进度的安排进行相应的检查 展示GitHub当日代码/文档签入记 ...
- 分布式CAP理论介绍:一致性(Consistency),可用性(Availability),容忍网络分区(Partition tolerance)
在理论计算机科学中,CAP定理(CAP theorem),又被称作布鲁尔定理(Brewer's theorem),它指出对于一个分布式计算系统来说,不可能同时满足以下三点: 一致性(Consisten ...
- 【Three.js】OrbitControl 旋转
一.摘要 分析了OrbitControl的基本原理. 二.资源 源码地址: 三.分析 最外层框架:OrbitControl 为函数对象,原型处理 THREE.OrbitControls = funct ...