Qt的内存管理机制

在Qt中,显式使用new创建的对象通常不需要显式调用delete来释放内存 ,这是因为Qt提供了一种基于对象树(Object Tree)和父子关系(Parent-Child Relationship)的内存管理机制 。这种机制可以自动管理对象的生命周期,确保在适当的时候释放内存:

在Qt中,每个QObject或其派生类(如QWidget、QPushButton)都可以有一个父对象(Parent)。

当创建一个对象时,如果指定了父对象,则该对象会被添加到父对象的子对象列表中。

当父对象被销毁时,Qt会自动递归销毁其所有子对象,从而释放内存。

QObject的析构函数会遍历其子对象列表,并递归调用每个子对象的析构函数。这种机制确保了所有子对象都会被正确释放。

显式调用delete仅在对象没有父对象或需要手动管理生命周期时才需要。

对象树

(1).QObject在对象树中自我组织(QObjects organize themselves in object trees)。当你创建一个以另一个对象为父对象的QObject时,它会被添加到父对象的 children()列表中,并在父对象被删除时被删除。事实证明,这种方法非常适合GUI对象的需求。例如,QShortcut(键盘快捷键)是相关窗口的子对象,因此当用户关闭该窗口时,快捷方式也会被删除。

(2).QWidget是Qt Widgets模块的基类,它扩展了父子关系(parent-child relationship)。QWidget继承自QObject、QPaintDevice。

(3).你还可以自行删除子对象,这些子对象会从其父对象中移除

(4).每个QObject都可以参与对象树。每个QObject都有一个子对象列表,也可能有一个父QObject。当QObject被销毁时,其所有附加子对象都会随之销毁。

对象树(Object Tree)是由父对象(Parent Object)及其子对象(Child Objects)构成的树状结构。在这个结构中,每一个对象都可以拥有子对象,而每个子对象又只能有一个父对象。这种父子关系不仅反映了对象之间的层级结构,还意味着当父对象被销毁时,所有的子对象也将被自动销毁。

QObject构造/析构顺序:当QObject在堆(heap)上创建时(即使用new创建),可以按任意顺序从它们构建树,之后,可以按任意顺序销毁树中的对象。当删除树中的任何QObject时,如果该对象有父对象,则析构函数会自动从其父对象中删除该对象。如果该对象有子对象,则析构函数会自动删除每个子对象。无论析构顺序如何,都不会删除两次QObject。

QObject包含许多用于检查此对象树的方法:

(1).parent():获取对象的父对象,或为null。

(2).setParent():设置对象的父对象。

(3).children():获取属于该对象的子对象列表。

在Qt框架中,几乎所有的事物都是对象。对象通常使用动态内存分配(Dynamic Memory Allocation)创建,即通过new关键字。在Qt中,当一个对象被创建时,可以指定另一个对象作为它的父对象。这种关系建立后,子对象的生命周期便与父对象紧密相关。当父对象被销毁时,它会自动销毁其所有子对象,从而保证资源的正确释放。

C++中的继承主要用于代码复用和多态性,而Qt中的父子关系主要用于内存管理和对象生命周期的控制

下载Qt6.8源码:

bash 复制代码
git clone git://code.qt.io/qt/qt5.git
cd qt5
git submodule update --init --recursive
git checkout v6.8.0

以下为测试代码:

cpp 复制代码
#include <QObject>
#include <QDebug>

namespace {

class MyObject : public QObject {
public:
	explicit MyObject(const QString& name, QObject* parent = nullptr) : QObject(parent), name_(name)
	{
		qDebug() << "Constructor: " << name_;
	}

	~MyObject()
	{
		qDebug() << "Destructor: " << name_;
	}

	QString name() const
	{
		return name_;
	}

private:
	QString name_{};
};

} // namespace

int test_memory_management()
{
	MyObject* parent = new MyObject("parent object");
	
	MyObject* child1 = new MyObject("child object1", parent);

	//MyObject* child2 = new MyObject("child object2", parent);
	MyObject* child2 = new MyObject("child object2");
	child2->setParent(parent);

	for (auto obj : parent->children()) {
		qDebug() << "child object name: " << ((MyObject*)obj)->name();
	}

	qDebug() << "child2 parent object name: " << ((MyObject*)child2->parent())->name();

	delete parent; // manually delete the parent object
	return 0;
}

执行结果如下图所示:

GitHubhttps://github.com/fengbingchun/Qt_Test

相关推荐
hqwest25 分钟前
码上通QT实战29--系统设置04-用户操作管理
开发语言·qt·模态窗体·addbindvalue·bindvalue
SunkingYang4 小时前
QT如何读取csv文件
c++·qt·csv·读取文件
SunkingYang5 小时前
QT中如何使用QMessageBox 实现提示、警告、错误报告和用户决策功能
c++·qt·提示·错误·告警·用法·qmessagebox
youqingyike6 小时前
Qt 中 QWidget 调用setLayout 后不显示
开发语言·c++·qt
_OP_CHEN6 小时前
【从零开始的Qt开发指南】(二十二)Qt 音视频开发宝典:从音频播放到视频播放器的实战全攻略
开发语言·c++·qt·音视频·前端开发·客户端开发·gui开发
Antony_WU_SZ6 小时前
QT Qmake 方式在visual studio中的 环境配置
开发语言·qt
Larry_Yanan6 小时前
Qt安卓开发(三)双摄像头内嵌布局
android·开发语言·c++·qt·ui
github.com/starRTC7 小时前
小白QT之QGraphicsScene场景视图
qt
hqwest8 小时前
码上通QT实战27--系统设置02-加载用户列表
开发语言·qt·sqlite·qtablewidget
电子_咸鱼9 小时前
Linux IPC 实战:管道与共享内存的使用场景 + 底层原理全剖析
linux·运维·服务器·开发语言·网络·vscode·qt