
一、Qt智能指针体系1.QPointer弱指针// QPointer只能用于QObject及其派生类QPointerQPushButton button new QPushButton(Click me);// 检查指针是否有效if (!button.isNull()) {button-setText(Clicked);}// 当对象被删除时QPointer自动置为nullptrdelete button.data(); // button.isNull()现在返回true2.QSharedPointer共享指针// 引用计数智能指针QSharedPointerMyObject obj1 QSharedPointerMyObject::create();QSharedPointerMyObject obj2 obj1; // 引用计数1// 自定义删除器QSharedPointerFILE file(fopen(test.txt, r), fclose);// 从裸指针转换谨慎使用MyObject* rawPtr new MyObject();QSharedPointerMyObject sharedPtr(rawPtr);3.QWeakPointer弱引用指针QSharedPointerMyObject shared QSharedPointerMyObject::create();QWeakPointerMyObject weak shared;// 提升为强引用QSharedPointerMyObject strong weak.toStrongRef();if (!strong.isNull()) {// 对象仍然存在}4.QScopedPointer作用域指针// 超出作用域自动删除{QScopedPointerMyClass ptr(new MyClass());ptr-doSomething();} // 这里自动删除// 自定义删除器QScopedPointerFILE, QScopedPointerPodDeleter file(fopen(test.txt, r));5.QSharedDataPointer隐式共享指针class SharedData : public QSharedData {public:SharedData() : value(0) {}SharedData(const SharedData other) : QSharedData(other), value(other.value) {}int value;};class MyClass {public:MyClass() : data(new SharedData) {}void setValue(int val) {// 写时复制Copy-On-Writedata-value val;}private:QSharedDataPointerSharedData data;};二、Qt对象树与父子关系指针1.QObject父子关系QWidget* parent new QWidget();QPushButton* child1 new QPushButton(Button 1, parent);QPushButton* child2 new QPushButton(Button 2, parent);// 删除父对象时自动删除所有子对象delete parent; // child1和child2也被自动删除// 查找子对象QObject* found parent-findChildQPushButton*(Button 1);2.对象所有权转移// 方法1在构造函数中指定父对象QObject* child new QObject(parent);// 方法2使用setParentQObject* child new QObject();child-setParent(parent);// 方法3使用QWidget的布局系统QWidget* widget new QWidget();QVBoxLayout* layout new QVBoxLayout(widget);QPushButton* button new QPushButton();layout-addWidget(button); // 所有权转移给widget三、信号槽中的指针管理1.安全的跨线程指针传递// 在主线程创建对象Worker* worker new Worker();// 移动到工作线程worker-moveToThread(workerThread);// 使用QPointer确保安全访问QPointerWorker safeWorker worker;connect(worker, Worker::finished, [safeWorker]() {if (safeWorker) {// 安全地使用worker}});2.使用智能指针连接信号槽QSharedPointerQObject obj QSharedPointerQObject::create();// 注意如果使用lambda捕获shared_ptr会延长对象生命周期connect(sender, Sender::signal, [obj]() {// obj会一直存在直到连接断开});// 更好的方式使用弱指针QWeakPointerQObject weakObj obj;connect(sender, Sender::signal, [weakObj]() {QSharedPointerQObject strong weakObj.toStrongRef();if (strong) {// 对象还存在}});四、内存管理最佳实践1.常见陷阱与解决方案// 陷阱1悬挂指针void problematic() {QObject* obj new QObject();// ... 使用objdelete obj;// 后续代码可能意外访问已删除的obj}// 解决方案使用智能指针void solution() {QScopedPointerQObject obj(new QObject());// 自动管理生命周期}// 陷阱2循环引用class A {QSharedPointerB b;};class B {QSharedPointerA a; // 循环引用};// 解决方案使用弱指针class B {QWeakPointerA a; // 打破循环};2.自定义删除器示例// 为第三方库资源创建自定义删除器struct SqliteDeleter {void operator()(sqlite3* db) {if (db) sqlite3_close(db);}};using SqlitePtr QScopedPointersqlite3, SqliteDeleter;SqlitePtr database(sqlite3_open(database.db));五、调试与检测工具1.内存泄漏检测#define QT_DEBUG_POINTERSclass MyClass : public QObject {Q_OBJECTpublic:MyClass(QObject* parent nullptr) : QObject(parent) {qDebug() MyClass created at this;}~MyClass() {qDebug() MyClass destroyed at this;}};// 在.pro文件中添加DEFINES QT_DEBUG_POINTERS2.使用valgrind检测# 运行内存检测valgrind --toolmemcheck --leak-checkfull ./your-qt-app# 使用Qt特定选项export QT_DEBUG_PLUGINS1valgrind ./your-qt-app六、性能优化建议避免频繁分配/释放使用对象池或预分配选择合适的指针类型根据使用场景选择注意信号槽连接及时断开不需要的连接使用移动语义C11的移动构造减少拷贝【总结】Qt提供了丰富的指针管理工具关键在于根据具体场景选择合适的指针类型QObject派生类优先使用父子关系管理资源共享使用QSharedPointer独占资源使用QScopedPointer或std::unique_ptr观察者模式使用QPointer隐式共享数据使用QSharedDataPointer七、Qt智能指针完整实例应用1.项目源码1.1 qpointer_example.h#ifndef QPOINTER_EXAMPLE_H#define QPOINTER_EXAMPLE_H#include QObject#include QPointer#include QPushButton#include QWidgetclass QPointerExample{public:static void demonstrate(QWidget *parent);};// 测试类class TestButton : public QPushButton{Q_OBJECTpublic:explicit TestButton(const QString text, QWidget *parent nullptr): QPushButton(text, parent){setObjectName(TestButton_ text);}~TestButton(){// 析构函数中输出信息}};#endif // QPOINTER_EXAMPLE_H1.2 qpointer_example.cpp#include qpointer_example.h#include QDebug#include QTimer#include QApplicationvoid QPointerExample::demonstrate(QWidget *parent){Q_UNUSED(parent);// 使用qDebug输出会被自定义消息处理器捕获auto log [](const QString msg) {qDebug() msg;};log(【示例1】创建QPointer并检查有效性);QPointerTestButton button new TestButton(点击我, parent);if (!button.isNull()) {log(QString(按钮创建成功对象名: %1).arg(button-objectName()));log(QString(按钮文本: %1).arg(button-text()));}log(\n【示例2】QPointer自动检测对象删除);QPointerTestButton button2 new TestButton(临时按钮, parent);log(QString(创建后检查: button2.isNull() %1).arg(button2.isNull() ? true : false));// 删除对象delete button2.data();log(QString(删除后检查: button2.isNull() %1).arg(button2.isNull() ? true : false));log(✓ QPointer自动检测到对象已被删除自动置为nullptr);log(\n【示例3】QPointer在多线程环境中的安全性);QPointerTestButton safeButton new TestButton(安全按钮, parent);// 模拟异步操作QTimer::singleShot(100, [safeButton, log]() {if (!safeButton.isNull()) {log(异步操作中对象仍然存在可以安全使用);safeButton-setText(已更新);} else {log(异步操作中对象已被删除QPointer保护了我们);}});log(\n【示例4】QPointer与普通指针的对比);TestButton *rawPtr new TestButton(裸指针按钮, parent);QPointerTestButton smartPtr new TestButton(智能指针按钮, parent);delete rawPtr;delete smartPtr.data();// 危险裸指针不会自动变为nullptrlog(QString(裸指针删除后: rawPtr %1 (危险可能指向已删除的内存)).arg(rawPtr ? 非空 : 空));log(QString(QPointer删除后: smartPtr.isNull() %1 (安全)).arg(smartPtr.isNull() ? true : false));log(\n【示例5】QPointer在容器中的使用);QListQPointerTestButton buttonList;for (int i 0; i 3; i) {buttonList.append(new TestButton(QString(按钮 %1).arg(i 1), parent));}log(QString(创建了 %1 个按钮).arg(buttonList.size()));// 删除部分按钮delete buttonList[1].data();// 安全遍历int validCount 0;for (const QPointerTestButton btn : buttonList) {if (!btn.isNull()) {validCount;log(QString(有效按钮: %1).arg(btn-text()));}}log(QString(有效按钮数量: %1).arg(validCount));log(\n【重要提示】);log(✓ QPointer只能用于QObject及其派生类);log(✓ QPointer不会延长对象生命周期);log(✓ QPointer主要用于观察者模式避免悬挂指针);log(✓ 适合用于缓存、回调等场景);}1.3 qsharedpointer_example.h#ifndef QSHAREDPOINTER_EXAMPLE_H#define QSHAREDPOINTER_EXAMPLE_H#include QObject#include QSharedPointer#include QDebugclass QWidget;class QSharedPointerExample{public:static void demonstrate(QWidget *parent);};// 测试类 - 非QObject派生类class MyData{public:MyData(int id 0) : m_id(id), m_value(0) {qDebug() QString(MyData[%1] 构造函数被调用).arg(m_id);}~MyData() {qDebug() QString(MyData[%1] 析构函数被调用).arg(m_id);}void setValue(int value) { m_value value; }int getValue() const { return m_value; }int getId() const { return m_id; }private:int m_id;int m_value;};// QObject派生类class MyObject : public QObject{Q_OBJECTpublic:explicit MyObject(int id, QObject *parent nullptr): QObject(parent), m_id(id) {qDebug() QString(MyObject[%1] 构造函数被调用).arg(m_id);}~MyObject() {qDebug() QString(MyObject[%1] 析构函数被调用).arg(m_id);}int getId() const { return m_id; }private:int m_id;};#endif // QSHAREDPOINTER_EXAMPLE_H1.4 qsharedpointer_example.cpp#include qsharedpointer_example.h#include QDebug#include QList#include QTimervoid QSharedPointerExample::demonstrate(QWidget *parent){Q_UNUSED(parent);auto log [](const QString msg) {qDebug() msg.toUtf8().constData();};log(【示例1】基本使用 - 引用计数);{QSharedPointerMyData ptr1 QSharedPointerMyData::create(1);log(创建ptr1);QSharedPointerMyData ptr2 ptr1;log(ptr2 ptr1引用计数增加);QSharedPointerMyData ptr3 ptr2;log(ptr3 ptr2引用计数再次增加);log(注意Qt 6中QSharedPointer不提供use_count()方法);log(离开作用域所有指针销毁对象自动删除);}log(对象已自动删除析构函数被调用);log(\n【示例2】从裸指针创建谨慎使用);{MyData *rawPtr new MyData(2);QSharedPointerMyData sharedPtr(rawPtr);log(从裸指针创建QSharedPointer);// 注意不要手动delete rawPtrQSharedPointer会管理// delete rawPtr; // 错误会导致双重删除}log(\n【示例3】自定义删除器);{// 模拟文件句柄struct FileHandle {QString filename;FileHandle(const QString name) : filename(name) {qDebug() QString(打开文件: %1).arg(filename);}~FileHandle() {qDebug() QString(关闭文件: %1).arg(filename);}};auto fileDeleter [](FileHandle *handle) {if (handle) {qDebug() QString(使用自定义删除器关闭: %1).arg(handle-filename);delete handle;}};QSharedPointerFileHandle file(new FileHandle(test.txt),fileDeleter);log(文件句柄由QSharedPointer管理);}log(文件自动关闭);log(\n【示例4】在容器中使用);{QListQSharedPointerMyData dataList;QSharedPointerMyData shared QSharedPointerMyData::create(3);dataList.append(shared);dataList.append(shared);dataList.append(shared);log(列表中有3个元素都共享同一个对象引用计数为3);QSharedPointerMyData another QSharedPointerMyData::create(4);dataList.append(another);log(添加新对象后列表中有4个元素前3个共享第4个独立);}log(\n【示例5】QObject派生类的使用);{QSharedPointerMyObject obj1 QSharedPointerMyObject::create(5);QSharedPointerMyObject obj2 obj1;log(obj1和obj2共享同一个对象引用计数为2);// QObject可以设置父对象QSharedPointerMyObject obj3 QSharedPointerMyObject::create(6, obj1.data());log(obj3的父对象是obj1);}log(\n【示例6】检查指针有效性);{QSharedPointerMyData ptr QSharedPointerMyData::create(7);if (ptr) {log(指针有效可以使用);ptr-setValue(100);log(QString(设置值: %1).arg(ptr-getValue()));}ptr.clear();if (ptr.isNull()) {log(指针已清空isNull()返回true);}}log(\n【示例7】弱引用检查与QWeakPointer配合);{QSharedPointerMyData strong QSharedPointerMyData::create(8);log(创建强引用);// 创建弱引用不影响引用计数// 这里只是演示实际使用见QWeakPointer示例log(可以创建QWeakPointer来观察对象而不增加引用计数);}log(\n【重要提示】);log(✓ QSharedPointer使用引用计数管理内存);log(✓ 最后一个引用销毁时对象自动删除);log(✓ 适合多个地方共享同一个对象);log(✓ 线程安全的引用计数Qt 5.14);log(✓ 注意避免循环引用使用QWeakPointer解决);}