【QT】对象树

一、QT对象树的概念

先来看一下 QObject 的构造函数:

img

通过帮助文档我们可以看到,QObject 的构造函数中会传入一个 Parent 父对象指针,children() 函数返回 QObjectList。即每一个 QObject 对象有且仅有一个父对象,但可以有很多个子对象。按照这种形式排列就会形成一个对象树的结构,最上层是父对象,下面是子对象,在再下面是孙子对象,以此类推。

那么Qt为什么要这么设计呢?或者说这样设计的好处是什么呢?很简单,就是为了方便内存管理。我们在创建 QObject 对象时,提供一个父对象,那么我们创建的这个 QObject 对象会自动添加到其父对象的 children() 列表。当父对象析构的时候,这个子对象列表中的所有对象都会被析构,当析构子对象的时候,会自动从父对象的子对象列表中删除

这种机制在 GUI 程序开发过程中是相当实用的。有一个很明显的现象就是我们会在窗口中new很多控件,但是却没有delete,因为在父控件销毁时这些子控件以及布局管理器对象会一并销毁。

值得注意的是,如果在构造时设置父对象为 NULL,那么当前实例不会有父对象存在,Qt 也不会自动析构该实例,除非实例超出作用域导致析构函数被调用,或者用户在恰当时机使用 delete 操作符或者使用 deleteLater 方法。


在这里插入图片描述


QWidget

QWidget 也是 QObject 的子类,所以在 parent 机制上是没有区别的。然而实际使用时,对于 QWidget 和其派生类来说,在内存管理上要稍微复杂一些。因为 QWidget 需要和 QEventLoop 高度配合才能完成工作,我们举个例子来说明一下。

例如 QWidget 的关闭流程,首先用户点击关闭按钮触发 close() 槽,然后Qt向 widget 发送 QCloseEvent,默认的 QCloseEvent 会将 widget 隐藏起来,也就是hide()。我们可以看到,widget 的关闭实际是将其隐藏,而没有释放内存,虽然我们有时会重写 closeEvent 但也不会手动释放 widget。

所以需要设置 Qt::WA_DeleteOnClose 属性,那么会在 close 之后接着调用 widget 的析构函数,或者手动 delete。




二、对象树模型存在的小问题

示例代码1:

#include <QApplication>
#include <QPushButton>int main(int argc, char *argv[])
{QApplication a(argc, argv);QPushButton btn("button");QWidget w;btn.setParent(&w);w.show();return a.exec();
}

运行结果: 关闭 widget 后程序崩溃,没有正常结束

程序异常结束。

原因:

btn.setParent(&w);

btn对象,通过setParent()函数,将自己挂到对象树上。当程序结束时,根据栈区的特性,应该是先析构父对象–w,再析构btn可是由于Qt中的对象树自动析构原理,我们析构父对象会自动析构子对象。也就是说,在析构父对象–w时,会自动调用子对象btn的析构函数。然后,栈区继续销毁,按照顺序还要再一次析构btn。但是这时候已经是第二次调用 子对象的析构函数了,C++中不允许调用两次析构函数,因此,程序会崩溃。


在这里插入图片描述




三、正确写法–尽量在堆上创建子对象

示例代码2:

#include <QApplication>
#include <QPushButton>int main(int argc, char *argv[])
{QApplication a(argc, argv);QPushButton *btn = new QPushButton ("button");QWidget *w = new QWidget;btn->setParent(w);w->show();return a.exec();
}

w和btn被分配在堆上。w析构时,不会影响在栈区中的对象,程序正常运行。


由此我们可以看到,Qt 的对象树机制虽然在内存管理上很方便,但是也会带来一些麻烦,为了避免这些麻烦我们可以这么做:

  1. 先创建父对象再创建子类对象,并且在创建子对象时就指定父对象;
  2. 尽量在堆上创建子对象;



参考链接:

Qt 对象树

Qt中的内存泄漏

[Qt源码阅读(三) 对象树管理]

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/119204.shtml

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

相关文章

美颜SDK集成指南:为应用添加视频美颜功能

随着社交媒体和直播应用的兴起&#xff0c;视频美颜功能已成为用户追求的一项热门特性。用户希望能够在拍摄照片或进行实时视频直播时&#xff0c;使用美颜功能来增强其外观。为了满足这一需求&#xff0c;开发者可以考虑集成美颜SDK&#xff0c;为其应用增加这一吸引人的功能。…

RabbitMQ原理(四):MQ的可靠性

消息到达MQ以后,如果MQ不能及时保存,也会导致消息丢失,所以MQ的可靠性也非常重要。 文章目录 2.1.数据持久化2.1.1.交换机持久化2.1.2.队列持久化2.1.3.消息持久化2.2.LazyQueue2.2.1.控制台配置Lazy模式2.2.2.代码配置Lazy模式2.2.3.更新已有队列为lazy模式2.1.数据持久化…

uniapp接口请求api封装,规范化调用

封装规范和vue中的差不多&#xff0c;都是统一封装成一个request对象&#xff0c;然后在api.js里面调用。 先创建一个utils文件夹&#xff0c;然后里面创建一个request.js&#xff0c;代码如下&#xff1a; export const baseURL 基础url地址const request (options) > …

面试题:线程池执行的用户任务抛出异常会怎样?

文章目录 ThreadPoolExecutor.execute源码分析 ThreadPoolExecutor.submit源码分析 ScheduledThreadPoolExecutor.schedule源码分析 思考&#xff1a;ThreadPoolExecutor.execute发生异常时为什么要退出 ThreadPoolExecutor.execute 源码分析 看源码可以知道&#xff0c;Thre…

alibaba.fastjson的使用(二)-- jar包导入

目录 1. 在pom文件中引入依赖: 2.fastjsonv2的使用: 1. 在pom文件中引入依赖: <dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>2.0.14</version> </dependency>2.fastjsonv2的使用…

npm换更换淘宝镜像

winr 进cmd &#xff0c;输入&#xff1a; npm install -g nrm open8.4.2 --save 安装完成后 nrm use taobao

VScode连接的服务器上使用jupyter显示请选择内核源

问题复现 我实在VScode上用ssh-remote连接的服务器&#xff0c;想用.ipynb文件上写东西&#xff0c;结果窗口上方弹出一个输入框&#xff0c;“请键入以选择内核”&#xff1b; 在扩展里找到jupyter更新一下 之前左边的图标是灰色的&#xff0c;后来我下下载了新的版本&#…

Xcode自定义快捷键

一、新建脚本 1. 编写脚本 把脚本sh文件保存在安全的目录&#xff0c;不会被删除 我这里主要是两个常用的&#xff1a; 1.打开终端: xcode-terminal.sh #!/bin/shif [ -n "$XcodeProjectPath" ]; then open -a Terminal "$XcodeProjectPath"/.. elseo…

使用Google的地点自动补全功能

一、前言 在进行海外开发时候需要使用google地图&#xff0c;这里对其中的地点自动补全功能开发进行记录。这里着重于代码开发&#xff0c;对于key的申请和配置不予记录。 二、基础配置 app文件夹下面的build.gradle plugins {// ...id com.google.android.libraries.mapsp…

数据挖掘和大数据的区别

数据挖掘 一般用于对企业内部系统的数据库进行筛选、整合和分析。 操作对象是数据仓库&#xff0c;数据相对有规律&#xff0c;数据量较少。 大数据 一般指对互联网中杂乱无章的数据进行筛选、整合和分析。 操作对象一般是互联网的数据&#xff0c;数据无规律&#xff0c;…

“淘宝” 开放平台接口设计思路|开放平台接口接入流程教程

最近对接的开放平台有点多&#xff0c;像淘宝、京东、快手、抖音等电商平台的开放平台基本对接了个遍&#xff0c;什么是CRUD BODY也许就是这样的吧&#xff01;&#xff01;&#xff01; 虽然对接各大开放平台没啥技术含量&#xff0c;但咱也得学点东西不是&#xff0c;不能白…

使用canvas实现时间轴上滑块的各种常用操作(仅供参考)

一、简介 使用canvas&#xff0c;模拟绘制时间轴区域&#xff0c;有时间刻度标尺&#xff0c;时间轴区域上会有多行&#xff0c;每行都有一个滑块。 1、时间刻度标尺可以拖动&#xff0c;会自动对齐整数点秒数&#xff0c;最小步数为0.1秒。 2、滑块可以自由拖动&#xff0c…

VR全景拍摄市场需求有多大?适用于哪些行业?

随着VR全景技术的成熟&#xff0c;越来越多的商家开始借助VR全景来宣传推广自己的店铺&#xff0c;特别是5G时代的到来&#xff0c;VR全景逐渐被应用在我们的日常生活中的各个方面&#xff0c;VR全景拍摄的市场需求也正在逐步加大。 通过VR全景技术将线下商家的实景“搬到线上”…

RTE2023大会来袭,声网宣布首创广播级4K超高清实时互动体验

10月24日&#xff0c;由声网和RTE开发者社区联合主办的RTE2023第九届实时互联网大会在北京举办&#xff0c;声网与众多RTE领域技术专家、产品精英、创业者、开发者一起&#xff0c;共同开启了以“智能高清”为主题的全新探讨。本届RTE大会将持续2天&#xff0c;开展1场主论坛及…

vm_flutter

附件地址 https://buuoj.cn/match/matches/195/challenges#vm_flutter 可以在buu下载到。 flutter我也不会&#xff0c;只是这个题目加密算法全部在java层&#xff0c;其实就是一个异或和相加。 反编译 package k;import java.util.Stack;/* loaded from: classes.dex */ pu…

Jupyter Notebook修改默认浏览器方法

Jupyter Notebook修改默认浏览器方法 Create a Jupyter Notebook Config file jupyter notebook --generate-config打开配置文件.jupyter/jupyter_notebook_config.py找到c.NotebookApp.browser 改成只向自己喜欢的浏览器路径’&#xff0c;这里给出选择google浏览器方法&…

vue3 setup写法点击跳转页面

1、push跳转 1.1、params传参&#xff0c;动态传参&#xff0c;数据会显示在地址栏中&#xff0c;且刷新页面不会消失 router.push({name: "MarineSpecialAddOrUpdate", //跳转的组件名字params: { //参数id: id,activeNames: "composition"}}) 1.2、qu…

Python基础入门例程12-NP12 格式化输出(二)

目录 描述 输入描述&#xff1a; 输出描述&#xff1a; 示例1 解答&#xff1a; 说明&#xff1a; 描述 牛牛、牛妹和牛可乐都是Nowcoder的用户&#xff0c;某天Nowcoder的管理员希望将他们的用户名以某种格式进行显示&#xff0c; 现在给定他们三个当中的某一个名字name…

淘宝API接口获取商品信息,订单管理,库存管理,数据分析

在淘宝开放平台中&#xff0c;每个API接口都有相应的文档说明和授权机制&#xff0c;以确保数据的安全性和可靠性。开发者可以根据自己的需求选择相应的API接口&#xff0c;并根据文档说明进行调用和使用。 淘宝开放平台API接口是一套REST方式的开放应用程序编程接口&…

web自动化测试——跨平台设备管理方案Selenium Grid

跨平台设备管理方案Selenium Grid 一、Selenium Grid简介二、使用场景场景一&#xff1a; 实现分布式执行测试&#xff0c;提高执行效率场景二&#xff1a; 解决浏览器兼容性问题新特性 三、Selenium Grid4原理分析四、环境安装五、运行方式&#xff1a;单机运行 - 独立模式1. …