Qt的4种智能指针:QScopedPointer,QSharedPointer,QWeakPointer,QPointer
2026/7/6 6:30:46 网站建设 项目流程

非AI生成,觉得有用,就请您帮忙点赞转发收藏吧,您的鼓励是我创作的动力,多谢看官。

目录

前言

C++中的智能指针简介

std::unique_ptr

std::shared_ptr

std:weak_ptr

Qt中的4中智能指针

QScopedPointer

QSharedPointer

QWeakPointer

QPointer

使用Qt的4种智能指针的完整示例

总结

参考链接


  • 前言

    C++中已经有了指针了,为什么还要整智能指针呢?
    C++没能通过编译器在语言层面实现内存安全,而是给程序员很大的自由,在早期的C++程序中容易出现内存访问错误(内存泄漏/悬空指针/双重释放等),这些错误有些比较隐蔽,不容易复现,导致排查也比较困难,这也是C++语言被有些人诟病的原因。
    由于C++指针的生命周期在程序中比较复杂,可能要跨函数、跨模块、多线程使用,这无疑加大了管理指针生命周期的难度,传统的裸指针应对这些场景,已经力不从心了,裸指针对内存资源的生命周期的表达能力已经不够用了。
    为了解决这些问题,C++11 标准正式引入了三种核心智能指针,均位于<memory>头文件中,旨在通过 ‌RAII(资源获取即初始化)‌ 机制自动管理动态内存,彻底解决手动delete导致的内存泄漏和悬空指针问题 。‌‌
  • C++中的智能指针简介

    • std::unique_ptr

      std::unique_ptr 是 C++11 引入的一种 轻量级 智能指针,它通过独占所有权和移动语义,提供了一种安全、高效的内存管理方式。它的主要优势包括:

      零开销:与裸指针相比几乎没有额外的内存开销
      独占所有权:避免了资源的重复释放
      移动语义:明确的所有权转移,避免了意外的拷贝
      支持数组:有专门的特化版本用于管理数组
      自定义删除器:可以处理特殊的资源释放逻辑

    • std::shared_ptr

      std::shared_ptr是一个基于引用计数的共享所有权的智能指针

      ✅ 可以被多个地方持有

      ✅ 引用计数归零时自动释放

      ✅ 线程安全(控制块)

      ✅ 异常安全

    • std:weak_ptr

      std::weak_ptr主要是用于和std::shared_ptr配合使用,解决循环引用导致内存资源无法释放的问题。std::weak_ptr对资源没有管辖权,不改变资源的强引用计数,只作为资源的观察者存在。
  • Qt中的4中智能指针

    • QScopedPointer<T>

      QScopedPointer是Qt专门设计的独占智能指针,基本等价于std::unique_ptr,但QScopedPointer不仅禁止拷贝,还禁止移动,这点是两者的最大区别。
    • QSharedPointer<T>

      ‌QSharedPointer 是 Qt 框架提供的共享所有权智能指针‌,通过引用计数自动管理动态对象的生命周期,当最后一个指向对象的 QSharedPointer 被销毁时,对象会自动释放,有效避免内存泄漏。‌‌‌
    • QWeakPointer<T>

      QWeakPointer是 Qt 框架提供的‌弱引用智能指针‌模板类,通常与QSharedPointer配合使用。它不拥有对象所有权,‌不会增加引用计数‌,因此不会阻止所指向对象的销毁,主要用于解决智能指针间的‌循环引用‌问题及安全观察对象生命周期 。‌‌
    • QPointer<T>

      QPointer 是 Qt 框架里的一种智能指针,专门用来安全地管理 QObject 及其子类对象的指针,当对象被销毁时它会自动变成空指针,防止程序崩溃‌。‌‌‌
      QPointer是 Qt 专门为 QObject设计的“防悬空指针工具”。
      Pointer在被观察的 QObject被销毁后,其内部指针会被自动置为 nullptr;QPointer对象本身仍然存在,只是不再指向有效对象。
      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 QScopedPointer<MyObject> myobj1(obj1); } void testSharedPointer(){ qDebug()<<"\n"; qDebug()<<"QSharedPointer测试"; auto obj = new MyObject("obj_shared"); QSharedPointer<MyObject> sp(obj); //共享智能指针,没有像标准C++的std::shared_ptr提供了引用计数接口:use_count() //类似标准C++的std::shared_ptr //执行赋值操作时会自动析构myobj2原先管理的对象obj2,旧对象的引用计数-1,引用计数为0时就会释放 //obj是在执行赋值操作:&operator=(const QSharedPointer &other)时释放的 sp = QSharedPointer<MyObject>::create("obj_shared_new"); } void testWeakPointer(){ qDebug()<<"\n"; qDebug()<<"QWeakPointer测试"; auto sp = QSharedPointer<MyObject>::create("obj"); //弱引用指针,没有对象管辖权 //类似标准C++的std::std::weak_ptr //QWeakPointer是对 QSharedPointer管理对象的非拥有引用,它观察的是"被共享的对象是否还活着",通过共享同一个控制块来判断 QWeakPointer<MyObject> 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 = QSharedPointer<MyObject>::create("obj"); //QPointer是 Qt 专门为 QObject设计的“防悬空指针工具” //Pointer在被观察的 QObject被销毁后,其内部指针会被自动置为 nullptr;QPointer对象本身仍然存在,只是不再指向有效对象 //QPointer不会变成 nullptr,而是它的 data()返回 nullptr //QWeakPointer技术上可以替代QPointer,但在Qt工程中,观察QObject永远应该用QPointer,QWeakPointer只适合非QObject的共享资源 QPointer<MyObject> 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.qInstallMessageHandler
    3.std::unique_ptr 复习





需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询