往期回顾:
【QT入门】 Qt内存管理机制详解
Qt中的内存管理主要是通过对象树和智能指针来实现的,下面一一列举各类方法:
一、对象树(Object Tree):
1、什么是对象数:
Qt中的对象可以形成一个层次结构,其中一个对象可以拥有子对象。当父对象被销毁时,它会自动销毁其所有子对象。这种父子关系形成了对象树。
Qt里所有类的最终父类是QObject。
而在Qt的ui设计里,QWidget是所有ui组件最大的父对象。QWidget继承于QObject。
2、内存管理方式:
当一个对象被添加为另一个对象的子对象时,Qt会自动管理子对象的内存,确保在父对象被销毁时,子对象也会被正确地销毁,从而避免内存泄漏。
对比C++派生类的内存管理方式:
构造顺序:先执行基类的构造函数,再执行派生类的构造函数
析构顺序:先执行派生类的析构函数,再执行基类的析构函数。
也就是说,QObject及其派生类的对象,如果其parent非空,那么其parent析构时会析构该对象
QWidget及其派生类的对象。
我们也可以设置Qt:WA__DeleteOnClose标志位,当close时会调用QWidgetPrivate::close_ _helper,进而调用deleteLater析构该对象。
3、示例
在一个Qt应用程序中,有一个主窗口 MainWindow,该窗口包含了一个按钮 QPushButton 和一个文本框 QLineEdit。当创建按钮和文本框时,可以将它们的父对象设置为主窗口 MainWindow,这样当主窗口关闭时,按钮和文本框会自动被销毁,无需手动管理它们的内存。
#include <QtWidgets>
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QMainWindow mainWindow;
QPushButton *button = new QPushButton("Click me", &mainWindow);
QLineEdit *lineEdit = new QLineEdit(&mainWindow);
mainWindow.show();
return app.exec();
}
二、智能指针(Smart Pointers):
Qt提供了 QSharedPointer 和 QWeakPointer 来管理对象的生命周期,从而简化内存管理。
1、QSharedPointer:
QSharedPointer 允许多个指针共享同一个对象,并且会在最后一个指针超出作用域时自动销毁对象。
2、QWeakPointer :
用于解决潜在的循环引用问题,避免内存泄漏。
3、示例:
在一个Qt应用程序中,有一个数据模型类 DataModel,该类负责管理一些数据对象。可以使用 QSharedPointer 来管理数据对象的生命周期,确保在不再需要数据对象时能够正确地释放内存,同时允许多个地方共享对数据对象的引用。
#include <QtWidgets>
class DataModel
{
public:
DataModel() {}
};
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QSharedPointer<DataModel> dataModel(new DataModel());
return app.exec();
}
三、信号槽机制:
1、为什么信号槽机制可以帮助管理内存:
因为Qt的信号槽机制可以用于对象之间的通信,而不需要直接引用对象的指针。这样就避免了内存管理问题,因为对象之间的连接是通过信号和槽进行的,而不是直接引用对象的指针。
2、示例:
在一个Qt应用程序中,有一个数据处理类 DataProcessor,该类负责处理数据并发出信号通知其他部分。其他部分可以通过连接信号和槽的方式来接收数据处理类发出的信号,而不需要直接引用数据处理类的指针,从而避免了可能的内存管理问题。
#include <QtWidgets>
class DataProcessor : public QObject
{
Q_OBJECT
public slots:
void processData()
{
qDebug() << "Processing data...";
emit dataProcessed();
}
signals:
void dataProcessed();
};
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
DataProcessor processor;
QObject::connect(&processor, &DataProcessor::dataProcessed, [](){
qDebug() << "Data processed signal received!";
});
processor.processData();
return app.exec();
}
四、代码示例
最后,用一个示例把几个方法综合起来看看:
#include <QtWidgets>
class CustomWidget : public QWidget
{
public:
CustomWidget(QWidget *parent = nullptr) : QWidget(parent)
{
// 设置父对象,建立父子关系
QPushButton *button = new QPushButton("Click me", this);
// 使用智能指针管理对象生命周期
QSharedPointer<QLineEdit> lineEdit(new QLineEdit(this));
// 连接信号槽
connect(button, &QPushButton::clicked, this, [lineEdit](){
QString text = lineEdit->text();
qDebug() << "Button clicked, LineEdit text: " << text;
});
}
};
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
// 创建主窗口作为对象树的根节点
QMainWindow mainWindow;
// 创建自定义小部件,设置其父对象为主窗口
CustomWidget customWidget(&mainWindow);
// 显示主窗口
mainWindow.show();
return app.exec();
}
1、代码内存管理分析:
|---------------------------------------------------------------|
| 1、CustomWidget 是一个自定义的小部件,它包含了一个按钮和一个文本框。 |
| 2、在 CustomWidget 的构造函数中,按钮和文本框的父对象都被设置为 CustomWidget,建立了父子关系。 |
| 3、使用 QSharedPointer 管理文本框对象的生命周期,确保在不再需要时能够正确释放内存。 |
| 4、通过信号与槽机制,按钮的点击事件与文本框文本的输出进行了连接,实现了对象之间的通信。 |
都看到这里了,点个赞再走呗朋友~
加油吧,预祝大家变得更强!