003-Qt 的对象管理

auther: abinng date: 2026-03-18 19:52 createDate:2026-03-18 19:51

主要逻辑

Qt 控件都会有一个父对象指针,依附于一个父对象,一旦父对象释放,父对象所有的子对象都会被自动析构,如下图:

当任何一个 QObject(不管是父是子)被销毁(调用析构函数)时,它会自动做两件事:

  1. 向下看(作为父对象): 遍历自己的子对象列表(Children List),对里面所有的子对象执行 delete 操作。

  2. 向上看(作为子对象): 通过 parent 指针找到自己的父对象,告诉父对象:“我要死了,请把我从你的子对象列表中移除掉。”(如果不做这一步,父对象以后析构时就会 delete 一个野指针导致崩溃)。

所以,无论你是手动 delete 了一个子对象,还是父对象被销毁引发了连锁反应,Qt 的这套机制都能保证内存安全。

在栈上创建对象时,会有释放顺序,如果先释放了父对象,再释放子对象,就会导致子对象多次释放,出错。所以一般会最上层的控件定义在栈上,下面管理的子控件申请在堆上

测试代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
#include <iostream>
#include <QApplication>
#include <string>

using std::cout;
using std::endl;

// 测试QT的自动内存管理

class Abinng : public QObject {
Q_OBJECT // 这里不加这个也能测试出对象内存管理
public:
explicit Abinng(QObject *parent = nullptr) : QObject(parent) {
cout <<__PRETTY_FUNCTION__ << endl;
}
~Abinng() override {
cout << __PRETTY_FUNCTION__ << endl;
}
};

class AbinngBlog : public QObject {
Q_OBJECT // 这里不加这个也能测试出对象内存管理
public:
explicit AbinngBlog(QObject *parent = nullptr) : QObject(parent) {
cout << __PRETTY_FUNCTION__ << endl;
}
~AbinngBlog() override {
cout << __PRETTY_FUNCTION__ << endl;
}
};

void test01() {
// 父对象定义在栈上,子对象都申请在堆上,交给父对象内存管理
QObject root;
Abinng *a1 = new Abinng(&root);
AbinngBlog *ab1 = new AbinngBlog(a1);
}

// 错误示范:父子都在栈上,且父对象在子对象之后创建
void badExample() {
QObject child; // 栈底,后析构
QObject parent; // 栈顶,先析构
child.setParent(&parent);

// 函数结束时栈展开(后进先出):
// 1. parent 先析构,它发现自己有个孩子 child,于是执行 delete &child; (崩溃!不能 delete 栈内存)
// 2. 就算没崩溃,栈接着销毁 child,又是一次析构。
}

int main(int argc, char *argv[]) {
QApplication a(argc, argv);

test01();
return 0;

// return a.exec();
}