Qt的4种智能指针:QScopedPointer,QSharedPointer,QWeakPointer,QPointer

发布时间:2026/7/6 6:30:56
Qt的4种智能指针:QScopedPointer,QSharedPointer,QWeakPointer,QPointer 非AI生成觉得有用就请您帮忙点赞转发收藏吧您的鼓励是我创作的动力多谢看官。目录前言C中的智能指针简介std::unique_ptrstd::shared_ptrstd:weak_ptrQt中的4中智能指针QScopedPointerQSharedPointerQWeakPointerQPointer使用Qt的4种智能指针的完整示例总结参考链接前言C中已经有了指针了为什么还要整智能指针呢C没能通过编译器在语言层面实现内存安全而是给程序员很大的自由在早期的C程序中容易出现内存访问错误内存泄漏/悬空指针/双重释放等这些错误有些比较隐蔽不容易复现导致排查也比较困难这也是C语言被有些人诟病的原因。由于C指针的生命周期在程序中比较复杂可能要跨函数、跨模块、多线程使用这无疑加大了管理指针生命周期的难度传统的裸指针应对这些场景已经力不从心了裸指针对内存资源的生命周期的表达能力已经不够用了。为了解决这些问题C11 标准正式引入了三种核心智能指针均位于memory头文件中旨在通过 ‌RAII资源获取即初始化‌ 机制自动管理动态内存彻底解决手动delete导致的内存泄漏和悬空指针问题 。‌‌C中的智能指针简介std::unique_ptrstd::unique_ptr 是 C11 引入的一种 轻量级 智能指针它通过独占所有权和移动语义提供了一种安全、高效的内存管理方式。它的主要优势包括零开销与裸指针相比几乎没有额外的内存开销独占所有权避免了资源的重复释放移动语义明确的所有权转移避免了意外的拷贝支持数组有专门的特化版本用于管理数组自定义删除器可以处理特殊的资源释放逻辑std::shared_ptrstd::shared_ptr是一个基于引用计数的共享所有权的智能指针✅ 可以被多个地方持有✅ 引用计数归零时自动释放✅ 线程安全控制块✅ 异常安全std:weak_ptrstd::weak_ptr主要是用于和std::shared_ptr配合使用解决循环引用导致内存资源无法释放的问题。std::weak_ptr对资源没有管辖权不改变资源的强引用计数只作为资源的观察者存在。Qt中的4中智能指针QScopedPointerTQScopedPointer是Qt专门设计的独占智能指针基本等价于std::unique_ptr但QScopedPointer不仅禁止拷贝还禁止移动这点是两者的最大区别。QSharedPointerT‌QSharedPointer 是 Qt 框架提供的共享所有权智能指针‌通过引用计数自动管理动态对象的生命周期当最后一个指向对象的 QSharedPointer 被销毁时对象会自动释放有效避免内存泄漏。‌‌‌QWeakPointerTQWeakPointer是 Qt 框架提供的‌弱引用智能指针‌模板类通常与QSharedPointer配合使用。它不拥有对象所有权‌不会增加引用计数‌因此不会阻止所指向对象的销毁主要用于解决智能指针间的‌循环引用‌问题及安全观察对象生命周期 。‌‌QPointerTQPointer 是 Qt 框架里的一种智能指针专门用来安全地管理 QObject 及其子类对象的指针当对象被销毁时它会自动变成空指针防止程序崩溃‌。‌‌‌QPointer是 Qt 专门为 QObject设计的“防悬空指针工具”。Pointer在被观察的 QObject被销毁后其内部指针会被自动置为 nullptrQPointer对象本身仍然存在只是不再指向有效对象。QPointer不会变成 nullptr而是它的 data()返回 nullptr。使用Qt的4种智能指针的完整示例#include QCoreApplication #include iostream #include QCoreApplication #include QDebug #include cstdio #include QScopedPointer #include QSharedPointer #include QWeakPointer #include QPointer #include QTimer #include QMutex #include QFile #include QDateTime //QObject的生命周期由父子对象树/deleteLater()/事件循环 共同决定 class MyObject:public QObject{ public: MyObject(QString objectName):m_objectName(objectName){ qDebug() objectName ,MyObject() 构造完成; } ~MyObject(){ qDebug() m_objectName ,~MyObject() 析构完成; } private: QString m_objectName; }; /* qDebug()内部使用的是行缓冲并不严格同步的输出流在以下情况下会出现“前面内容被后面内容冲掉/覆盖/错位” 1.多线程同时调用 qDebug() 2.不同线程的输出在 同一时刻写入标准输出 3.输出内容还没写完就被另一个线程的内容插队 */ //自定义全局消息处理函数 void myMessageOutput(QtMsgType type, const QMessageLogContext context, const QString msg) { static QMutex mutex; QMutexLocker locker(mutex);//加锁避免日志输出错乱 QString time QDateTime::currentDateTime().toString(yyyy-MM-dd hh:mm:ss.zzz); QString txt msg; if(msg ! \n){ txt QString([%1] %2).arg(time).arg(msg); } //QFile out(log.txt); //out.open(QIODevice::WriteOnly | QIODevice::Append); //QTextStream ts(out); //ts txt Qt::endl; qDebug().noquote()txt; } void testScopedPointer(){ qDebug()\n; qDebug()QScopedPointer测试; auto obj1 new MyObject(obj1); //独占智能指针作用域内唯一、不可转移的所有权obj1被它独享了myobj1和obj1共存亡 //类似标准C的std::unique_ptr QScopedPointerMyObject myobj1(obj1); } void testSharedPointer(){ qDebug()\n; qDebug()QSharedPointer测试; auto obj new MyObject(obj_shared); QSharedPointerMyObject sp(obj); //共享智能指针没有像标准C的std::shared_ptr提供了引用计数接口:use_count() //类似标准C的std::shared_ptr //执行赋值操作时会自动析构myobj2原先管理的对象obj2旧对象的引用计数-1引用计数为0时就会释放 //obj是在执行赋值操作:operator(const QSharedPointer other)时释放的 sp QSharedPointerMyObject::create(obj_shared_new); } void testWeakPointer(){ qDebug()\n; qDebug()QWeakPointer测试; auto sp QSharedPointerMyObject::create(obj); //弱引用指针没有对象管辖权 //类似标准C的std::std::weak_ptr //QWeakPointer是对 QSharedPointer管理对象的非拥有引用它观察的是被共享的对象是否还活着通过共享同一个控制块来判断 QWeakPointerMyObject wp sp; //调用 singleShot 的线程必须运行着事件循环exec()否则定时器永远不会触发 QTimer::singleShot(5000,[](){ qDebug() 5秒后执行QTimer::singleShot, (wp?object 还活着呢:object 已释放了,QWeakPointer能防【非QObject类型】的悬空指针呢); }); qDebug() testWeakPointer,obj对象是否还活着: !wp.isNull(); } void testPointer(){ qDebug()\n; qDebug()QPointer测试; auto sp QSharedPointerMyObject::create(obj); //QPointer是 Qt 专门为 QObject设计的“防悬空指针工具” //Pointer在被观察的 QObject被销毁后其内部指针会被自动置为 nullptrQPointer对象本身仍然存在只是不再指向有效对象 //QPointer不会变成 nullptr而是它的 data()返回 nullptr //QWeakPointer技术上可以替代QPointer但在Qt工程中观察QObject永远应该用QPointerQWeakPointer只适合非QObject的共享资源 QPointerMyObject p sp.data(); //调用 singleShot 的线程必须运行着事件循环exec()否则定时器永远不会触发 QTimer::singleShot(5000,[](){ qDebug() 5秒后执行QTimer::singleShot, (p?object 还活着呢:object 已释放了,QPointer能防【QObjec类型】悬空指针误用呢); }); qDebug() testPointer,obj对象是否还活着: !p.isNull(); } int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); qInstallMessageHandler(myMessageOutput);//注册自定义全局消息处理函数 qDebug() Qt智能指针测试; testScopedPointer(); testSharedPointer(); testWeakPointer(); testPointer(); /*QTextStream in(stdin); qDebug() Press q and Enter to quit...; while (!in.atEnd()) { QString line in.readLine(); if (line q) { qDebug() Exit by user.; return 0; } }*/ return a.exec(); }运行截图总结Qt 项目中推荐统一使用 Qt 提供的智能指针QScopedPointer / QSharedPointer / QWeakPointer / QPointer。​不要混用 Qt 智能指针和 C 标准智能指针来管理同一类资源。UI 控件QWidget / QObject 派生类一律使用 Qt 的对象树父子机制管理生命周期​不要使用任何 Qt 智能指针QSharedPointer / QScopedPointer / QPointer管理 UI 控件父对象删除子对象智能指针再次delete极容易出现双重释放的问题。参考链接1.避免常见陷阱qtimer::singleshot使用要点解析2.qInstallMessageHandler3.std::unique_ptr 复习