夫唯不争,故天下莫能与之争  -- 老子


在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)的更多相关文章

  1. Qt deletelater函数分析(1)

               生活的全部意义在于无穷地探索尚未知道的东西,在于不断地增加更多的知识.--左拉 该函数是QObject类的函数:                             ---- ...

  2. Qt源码分析之QObject

    原文:http://blog.csdn.net/oowgsoo/article/details/1529284 我感觉oowgsoo兄弟写的分析相当透彻,赞! 1.试验代码: #include < ...

  3. QT源码分析(从QApplication开始)

    QT源码分析 转载自:http://no001.blog.51cto.com/1142339/282130 今天,在给同学讲东西的时候,谈到了Qt源代码的问题,才发现自己对Qt机制的了解是在太少了,而 ...

  4. 31.QPainter-rotate()函数分析-文字旋转不倾斜,图片旋转实现等待

    在上章和上上上章: 28.QT-QPainter介绍 30.QT-渐变之QLinearGradient. QConicalGradient.QRadialGradient 学习了QPainter基础绘 ...

  5. split(),preg_split()与explode()函数分析与介

    split(),preg_split()与explode()函数分析与介 发布时间:2013-06-01 18:32:45   来源:尔玉毕业设计   评论:0 点击:965 split()函数可以实 ...

  6. string函数分析

    string函数分析string函数包含在string.c文件中,经常被C文件使用.1. strcpy函数原型: char* strcpy(char* str1,char* str2);函数功能: 把 ...

  7. start_amboot()函数分析

    一.整体流程 start_amboot()函数是执行完start.S汇编文件后第一个C语言函数,完成的功能自然还是初始化的工作 . 1.全局变量指针r8设定,以及全局变量区清零 2.执行一些类初始化函 ...

  8. uboot的jumptable_init函数分析

    一.函数说明 函数功能:安装系统函数指针 函数位置:common/exports.c 二.函数分析 void jumptable_init (void) { int i; gd->jt = (v ...

  9. Linux-0.11内核源代码分析系列:内存管理get_free_page()函数分析

    Linux-0.11内存管理模块是源码中比較难以理解的部分,如今把笔者个人的理解发表 先发Linux-0.11内核内存管理get_free_page()函数分析 有时间再写其它函数或者文件的:) /* ...

随机推荐

  1. c++处理字符串string.find()与string::npos

    1. string s  = “xxx”; int a = s.find(‘x’); 如果没有匹配到,那么a = string::npos;

  2. CLR 调试概述

    利用公共语言运行时 (CLR) 调试 API,工具供应商可以编写调试器来调试运行于 CLR 环境中的应用程序. 要调试的代码可为 CLR 支持的任何代码种类.CLR 调试 API 主要是使用非托管代码 ...

  3. 洛谷 P2421 [NOI2002]荒岛野人

    题目描述 又是一道扩欧的题. 要求一个最小的m使得 Ci+Pi*x≡Cj+Pj*x mod m(i!=j) 在x在第i个人和第j个人的有生之年无解. 也就是 (Pi-Pj)*x+m*y=Cj-Ci 在 ...

  4. 【loj2983】【WC2019】数树

    题目 两颗\(n\)个点的树T1和T2,有\(y\)种颜色; 现在给每个点染色,要求公共边端点的颜色相同,求: ​ 1.op=0 , T1和T2都确定,求合法染色方案数: ​ 2.op=1 , T1确 ...

  5. Angular2发送HTTP请求SpringBoot后台跨域问题解决

    Angular通过http发送post请求至SpringBoot的Controller,由于同源策略的保护,遇到跨域问题: • 源(origin)就是协议(http).域名(localhost)和端口 ...

  6. 洛谷P2659 美丽的序列

    题目 该题目可以用辅助数组l[i], r[i]来指向以data[i]为最小值的左端点和右端点.然后最后枚举每个data[i]寻找每个data[i]的美丽值的最大值. 然后辅助数组可以用单调栈求出. # ...

  7. Android Studio一直显示Building“project name”Gradle project info问题详解

    关注我,每天都有优质技术文章推送,工作,学习累了的时候放松一下自己. 本篇文章同步微信公众号  欢迎大家关注我的微信公众号:「醉翁猫咪」 Android Studio一直显示 Building&quo ...

  8. jmeter5实现mysql数据库值提取--单sql提取

    字段背景: 在进行接口测试或者压力测试过程中下文的请求需要用到上文请求的值,除了通过正则表达式的方式外,为了更准确的获得数据库值,我们可以直接从数据库提取 一.如何实现数据库的连接.此处不再赘述 点击 ...

  9. springMVC开启声明式事务实现操作日志记录

    第一步.在applicationContext-mvc.xml开启AOP注解扫描 <aop:aspectj-autoproxy/> 第二步.创建增强类,实现日志记录 @Component ...

  10. spring @Autowired注入map

    注入map,平常一般不会这么做,今天看一段老代码时发现有这么个用法.补习一下. @Autowired 标注作用于 Map 类型时,如果 Map 的 key 为 String 类型,则 Spring 会 ...