Qt对象树的销毁

2023-05-16

一、问题

在C++中中,我们都知道:delete 和 new 必须配对使用(一 一对应):delete少了,则内存泄露。

为什么Qt使用new来创建一个控件,但是却没有使用delete来进行释放?

二、对象树

Qt中使用对象树来组织和管理所有的QObject类及其子类的对象。

当创建一个QObject对象时,会看到QObject的构造函数接收一个QObject指针作为参数,这个参数就是 parent,也就是父对象指针。

每个 QObject 内部都有一个list,用来保存所有的 children,还有一个指针,保存自己的parent。当它自己被析构时,如果这个对象有 parent,则自动将其从 parent 的children()列表中删除;如果有孩子,则自动 delete 每一个孩子。

 比如Widget中的组件,如果是在堆上创建(使用new操作符),那么只要指定Widget为其父窗口(创建时指定parent参数为this)就可以了,也不需要进行delete操作。当整个应用程序关闭时,会去销毁该Widget对象,而此时又会自动销毁它的所有子组件,这些都是Qt的对象树所完成的。

三、对象树的实例

我们来分析一个Button对象的创建到销毁的过程。

创建一个MyPushButton对象,继承QPushButton

#ifndef MYPUSHBUTTON_H
#define MYPUSHBUTTON_H

#include <QPushButton>

class MyPushButton : public QPushButton
{
    Q_OBJECT
public:
    explicit MyPushButton(QWidget *parent = nullptr);
    ~MyPushButton();
};

#endif // MYPUSHBUTTON_H
#include "mypushbutton.h"
#include<QDebug>

MyPushButton::MyPushButton(QWidget *parent) : QPushButton(parent)

{
    qDebug()<<"MyPushButton construct";
}

MyPushButton::~MyPushButton()

{
    qDebug()<<"MyPushButton destory";
}

main函数

#include "mainwindow.h"
#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MainWindow w;
    w.show();
    return a.exec();
}

创建mainWindow

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>


QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

private:
    Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "mypushbutton.h"

#include<QtDebug>

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    qDebug()<<"MainWindow construct";

    ui->setupUi(this);

    MyPushButton *mybtn=new MyPushButton(this);

    mybtn->resize(120,50);

    mybtn->setText("MyPushButton");

    mybtn->move(200,20);
}


MainWindow::~MainWindow()
{
    delete ui;
    qDebug()<<"MainWindow destory";
}

MainWindow类的析构函数中默认已经有了销毁ui的语句,这里又添加了输出语句。
当MainWindow窗口被销毁时,将输出信息。下面运行程序,然后关闭窗口,在Qt Creator
的应用程序输出栏中的输出信息为:

 可能有读者问这里为什么是MyPushButton后销毁,难道不应该先销毁MyPushButton,再销毁MainWindows吗?

因为这里与Qt的实现有关,堆栈信息如下,deleteChildren 在MainWindows的父类QWidget的析构函数中,C++是子类对象先析构,再进行父类对象的析构,而MyPushButton在QWidget的析构函数中调用,所以顺序与我们预想的不一致。

四、总结

Qt 引入对象树的概念,在一定程度上解决了内存问题,但是也存在风险。

比如下面这段代码,程序崩溃了!!!

{
    QPushButton quit("Quit");

    QWidget window;

    quit.setParent(&window);
}

 分析:作为父对象的 window 会首先被析构,因为它是最后一个创建的对象。在析构过程中,它会调用子对象列表中每一个对象的析构函数,也就是说, quit 此时就被析构了。然后,代码继续执行,在 window 析构之后,quit 也会被析构,因为 quit 也是一个局部变量,在超出作用域的时候当然也需要析构。但是,这时候已经是第二次调用 quit 的析构函数了,C++ 不允许调用两次析构函数,因此,程序崩溃了。

所以,对于规范的Qt程序,我们在main()函数中将主窗口部件创建在栈上,比如“Widget w;”,而不要在堆上进行创建(使用new操作符),避免内存泄漏。对于子窗口部件,可以使用new操作符在堆上进行创建,同时一定要指定其父部件(parent),这样就不需要再使用delete操作符来销毁该对象了。

参考:

QT对象树 - 安静点-- - 博客园

Qt对象树_不想在北京做开发的博客-CSDN博客_qt 对象树

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Qt对象树的销毁 的相关文章

  • linux进程控制函数--fork,exec,exit,wait,sleep

    1 fork 在linux系统中 xff0c 用户创建进程的唯一方法就是使用系统调用fork xff0c 大概要进行下面的操作 lt 1 gt 分配表项 xff0c 一个用户的进程项是有限的 xff1b lt 2 gt 创建子进程的进程标识
  • linux的用户模式和内核模式

    MS DOS等操作系统在单一的CPU模式下运行 xff0c 但是一些类Unix的操作系统则使用了双模式 xff0c 可以有效地实现时间共享 在Linux机器上 xff0c CPU要么处于受信任的内核模式 xff0c 要么处于受限制的用户模式
  • 阿里内推面试经历

    写在最前 其实主观上并不是很想写 xff0c 但坚持写完是希望能分享给准备进互联网实习或工作的同学或朋友一些经验和收获
  • 关于利用Openmp中使用的时间函数

    Openmp是一项并行化技术 xff0c 是可以提高串行化程序的运行效率的 xff0c 但需要使用正确的时间函数来进行衡量 首先 xff0c 先提出一个unix linux下的内核时间获取函数和一个omp h的一个库函数 1 clock 函
  • mybatis之映射文件

    mybatis框架如何实现java语句与数据库语句的分离 映射文件 通过在映射文件中写入动态sql语句 xff0c 完成增删改查操作 映射文件中的元素都包含在根节点 lt mapper gt lt mapper gt 下 xff0c map
  • mybatis之高级查询

    Mybatis中的高级查询主要通过关联查询 xff0c 集合查询或鉴别器来完成 其核心就是之前提到的通过resultMap标记来完成 1 关联查询 关联查询一般有三种方式 xff1a a 联合查询 利用resultMap的map xml中的
  • mybaits之动态sql

    mybaits除了提供连接数据库 xff0c 使java和数据库语句分离之外 xff0c 还有一个显著的特点就是使用动态sql语句 这些sql语句均写在map映射文件中 xff0c 并通过一系列标记来完成 1 if标记 常用形式 xff1a
  • 平衡二叉树-的四种旋转调整(代码,图解)

    平衡二叉树 的四种旋转调整 xff08 代码 xff0c 图解 xff09 1 右单旋 xff1a 新插入节点插入在较高左子树的左侧 xff08 左左右 xff09 xff0c 插入新节点二十 xff1a 1 修改parent和curLR的
  • 头文件里一般会加入的宏定义,为了避免一个头文件被重复调用

    华清视频里讲的 xff0c 写代码的时候 xff0c 头文件一般地都会加上一个类似这样的宏 xff0c 希望你从此以后再写头文件 xff0c 加上一个宏 加了这个有一个好处 xff0c 当你第一次包含tree h的时候 xff0c 如果没定
  • 自己组装Pixhawk F450无人机的一些细节

    首先参考文档为 xff1a 1 https mp weixin qq com s VXKU kIB v i0AX3zgtLig 2 https mp weixin qq com s Qzzl dQ6Tz2pXNp7Oj0lTg 3 http
  • 电机和桨叶要搭配选择

    拍自 四旋翼无人机的制作与飞行
  • 接收机PPM与SBUS

    最开始是自己弄ACfly的飞控时发现插接收机有两个位置 xff0c 一个PPM一个SBUS xff0c 我想直接移植Pixhawk的接收机或者无名的接收机到ACfly模块上 我最后发现Pixhawk和无名的也是留了两个给接收机 xff08
  • 现在发现如果无人机的电机不同,浆可能是不能混用的。

    现在发现如果无人机的电机不同 xff0c 浆可能是不能混用的 孔位不同 xff0c 我之前在无名那里买了很多浆 xff0c 觉得这次F330的浆没了可以用那个替 xff0c 我刚刚试了下发现插不进去 xff0c 不能通用 包括我刚才在店家那
  • 无人机电池似乎可以并联,串联组合

    之前总是见到这种奇怪的线 xff0c 一直不知道作什么用 xff0c 现在大概清楚了 是不是这样可以实现更长时间的续航 xff0c 我之前再ACfly的群里看到一个人的六轴是上面放了两个电池的 xff0c 他这可能也是并联的
  • 任务的三要素是任务主体函数,任务栈和任务控制块

    任务的三要素是任务主体函数 xff0c 任务栈和任务控制块 由xTaskCreateStatic 函数来把三者联合起立 下面拍自野火的 FreeRTOS内核实现与应用开发实战指南
  • 如何用Realsense D435i运行VINS-Mono等VIO算法 获取IMU同步数据

    摘自 xff1a https blog csdn net qq 41839222 article details 86552367 如何用Realsense D435i运行VINS Mono等VIO算法 获取IMU同步数据 Manii 20
  • Opencv安装与环境配置

    转载自 xff1a https blog csdn net sm16111 article details 81238324 Opencv安装与环境配置 代码敌敌畏 2018 07 27 15 46 24 50411 收藏 94 分类专栏
  • 串口参数详解:波特率,数据位,停止位,奇偶校验位

    转载自 xff1a https blog csdn net sinat 35705952 article details 89034455 串口参数详解 xff1a 波特率 xff0c 数据位 xff0c 停止位 xff0c 奇偶校验位 W
  • cpp-httplib库简单原理,听说你还不会开源库?

    cpp httplib库的原理 听说你还不会开源库 xff1f 介绍httplib h头文件的处理流程httplib h头文件的组成httplib h头文件搭建服务端与客户端的原理Get接口listen 0 0 0 0 8989 接口 介绍
  • UART串口调试

    转载自 xff1a https www secpulse com archives 157847 html UART串口调试 脉搏文库 TideSec 2021 04 23 4 356 0x00前言 前段时间陆陆续续的对光猫 路由器 摄像头

随机推荐

  • visca协议及其实现的简单认识

    转载自 xff1a https latelee blog csdn net article details 35811777 visca协议及其实现的简单认识 李迟 2014 06 30 14 09 01 7064 收藏 12 分类专栏 x
  • C语言实现的一个简单的HTTP程序

    转载自 xff1a https www cnblogs com xuwenmin888 archive 2013 05 04 3059282 html C语言实现的一个简单的HTTP程序 以下是参考 lt winsock网络编程经络 gt
  • ideavim使用

    IdeaVim 常用操作 IdeaVim简介 IdeaVim是IntelliJ IDEA的一款插件 xff0c 他提高了我们写代码的速度 xff0c 对代码的跳转 xff0c 查找也很友好 安装之后它在 Tools gt Vim Emula
  • CAN总线——数据传输故障处理

    最近遇到CAN总线通讯的问题 上位机为arm板 xff0c 核心板为Cortex A9处理器 Linux内核 下位机为5块 STM32板 现象为 xff1a 如果上位机只接收数据 xff0c 一切通讯正常 当上位机下发命令 xff0c 那么
  • 升级构建工具,从Makefile到CMake

    更多博文 xff0c 请看音视频系统学习的浪漫马车之总目录 C C 43 43 编译 浅析C C 43 43 编译本质 一篇文章入门C C 43 43 自动构建利器之Makefile 升级构建工具 xff0c 从Makefile到CMake
  • RTKLIB简介

    RTKLIB是全球导航卫星系统GNSS global navigation satellite system 的标准 amp 精密定位开源程序包 xff0c RTKLIB由日本东京海洋大学 xff08 Tokyo University of
  • zzuli OJ 1038: 绝对值最大

    Description 输入3个整数 xff0c 输出绝对值最大的那个数 Input 输入包含3个int范围内的整数 xff0c 用空格隔开 Output 输出三个数中绝对值最大的数 xff0c 单独占一行 若绝对值最大的数不唯一 xff0
  • md5sum

    ERROR 1550456422 414780061 Client Lidar cipv 213 wants topic rs percept result to have datatype md5sum autodrive msgs Pe
  • libcurl实现HTTP

    关于libcurl的相关函数介绍以及参数详见官方说明 https curl haxx se libcurl c example html HTTP Request 一个http请求包含方法 路径 http版本 请求包头 请求方法 GET H
  • 深夜没事,抓个ARP包吧!

    深夜没事 xff0c 抓个ARP包吧 xff01 ipconfig查看网卡信息 选择en33这个网卡 xff0c 发送两次 xff0c 询问192 168 21 1的mac地址 xff0c 注意 xff1a ARP请求只能在同一子网内部进行
  • linux基础篇(一)——GCC和Makefile编译过程

    linux系列目录 xff1a linux基础篇 xff08 一 xff09 GCC和Makefile编译过程 linux基础篇 xff08 二 xff09 静态和动态链接 ARM裸机篇 xff08 一 xff09 i MX6ULL介绍 A
  • jni/ndk问题 :引用so库报错: java.lang.UnsatisfiedLinkError: No implementation found for

    问题 xff1a 引用so库报错 xff1a java span class token punctuation span lang span class token punctuation span UnsatisfiedLinkErro
  • 《python+opencv实践》一、基于颜色的物体追踪(上)

    点击打开链接 本文主要参考国外一大牛博客 xff0c 然后自己修改得来 相关知识点在这里 实现功能 xff1a 追踪红颜色瓶盖 xff0c 并画出瓶盖轮廓和运动轨迹 from collections import deque import
  • C++的sort函数实现字符串排序

    一 背景 sort函数用于C 43 43 中 xff0c 对给定区间所有元素进行排序 头文件是 include lt algorithm gt 实现原理 xff1a sort并不是简单的快速排序 xff0c 它对普通的快速排序进行了优化 x
  • C# 中的Dispose()用法

    一 对Dispose方法的理解是什么呢 xff1f 使用Dispose方法的对象 xff0c 应释放它拥有的所有资源 它还应该通过调用其父类型的Dispose方法释放其基类型拥有的所有资源 net的对象使用一般分为三种情况 1 创建对象 2
  • C++的 remove函数

    一 介绍 remove函数原型如下 xff1a template lt class ForwardIt class T gt ForwardIt remove ForwardIt first ForwardIt last const T a
  • 主板上的南桥与北桥

    一 历史 曾经 xff0c 北桥芯片和南桥芯片都是主板芯片组中最重要的组成部分 传统来说 xff0c 靠上方的叫北桥 xff0c 靠下方的叫南桥 北桥负责与CPU通信 xff0c 并且连接高速设备 xff08 内存 显卡 xff09 xff
  • CMake的add_library与target_link_libraries

    一 add library介绍 使用该命令可以在Linux下生成 xff08 静态 动态 xff09 库so或者 a文件 xff0c Windows下就是dll与lib文件 xff0c 它有两种命令格式 1 1 第一种格式 xff1a No
  • Linux下终止正在执行的shell脚本

    一 问题 Linux系统Shell中提交了一个脚本 xff0c 但是需要停止这个进程 xff0c 如何处理 xff1f 二 方案1 killall fileName 说明 xff1a killall是一个命令 xff0c 不是kill al
  • Qt对象树的销毁

    一 问题 在C 43 43 中中 xff0c 我们都知道 xff1a delete 和 new 必须配对使用 一 一对应 xff1a delete少了 xff0c 则内存泄露 为什么Qt使用new来创建一个控件 xff0c 但是却没有使用d