Qt QSharedPointer用法使用小结

2026-07-09编程代码43250

本文主要介绍了Qt QSharedPointer用法使用小结,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

目录
  • 一、核心机制:引用计数
  • 二、基本用法
    • 1. 创建 QSharedPointer
      • (1)从原始指针构造(需确保指针唯一由 QSharedPointer 管理)
      • (2)使用 QSharedPointer::create()(Qt 5.10+ 推荐)
      • (3)拷贝构造/赋值(共享所有权)
    • 2. 访问对象成员
      • 3. 重置(放弃所有权)
        • 4. 判断有效性
          • 5. 获取原始指针
          • 三、高级用法
            • 1. 自定义删除器(Deleter)
              • 2. 与 QWeakPointer 配合(解决循环引用)
              • 四、注意事项
                • 五、总结

                  QSharedPointer 是 Qt 提供的一个共享所有权的智能指针,用于自动管理动态分配对象的生命周期。它通过引用计数(Reference Counting)机制实现:当最后一个指向对象的 QSharedPointer 被销毁或重置时,对象会被自动 delete。这在 C++ 开发中能有效避免内存泄漏,尤其适合需要多模块共享资源的场景(如流媒体中的缓冲区、视频帧对象等)。

                  一、核心机制:引用计数

                  • 强引用计数:记录当前有多少个 QSharedPointer 指向同一个对象。
                  • 弱引用计数(通过 QWeakPointer):不增加强引用计数,仅观察对象是否存在(用于解决循环引用)。
                  • 当强引用计数降为 0 时,对象被自动释放。

                  二、基本用法

                  1. 创建 QSharedPointer

                  QSharedPointer 通常通过以下方式创建:

                  (1)从原始指针构造(需确保指针唯一由 QSharedPointer 管理)

                  #include 
                  #include 
                  
                  class MyClass {
                  public:
                      MyClass(int v) : value(v) { qDebug() << "MyClass constructed"; }
                      ~MyClass() { qDebug() << "MyClass destroyed"; }
                      int value;
                  };
                  
                  int main() {
                      // 从原始指针构造(注意:原始指针必须是通过 new 分配的)
                      QSharedPointer ptr(new MyClass(10)); 
                      return 0;
                  }
                  // 输出:
                  // MyClass constructed
                  // MyClass destroyed(main 结束时 ptr 析构,引用计数归零)

                  (2)使用 QSharedPointer::create()(Qt 5.10+ 推荐)

                  更安全的方式(避免原始指针暴露):

                  auto ptr = QSharedPointer::create(20); // 等价于 new MyClass(20),但更安全

                  (3)拷贝构造/赋值(共享所有权)

                  QSharedPointer ptr1(new MyClass(30));
                  QSharedPointer ptr2 = ptr1; // 拷贝构造,引用计数+1(变为2)
                  ptr1.reset(); // ptr1 放弃所有权,引用计数-1(变为1)
                  // 此时 ptr2 仍指向对象,main 结束时 ptr2 析构,对象被释放

                  2. 访问对象成员

                  通过 operator->operator*访问对象:

                  QSharedPointer ptr = QSharedPointer::create(40);
                  qDebug() <value; // 输出 40(等价于 (*ptr).value)

                  3. 重置(放弃所有权)

                  • reset():释放当前对象的所有权(若引用计数归零则删除对象),并置空。
                  • reset(T* other):释放当前对象,接管新对象的所有权。
                  QSharedPointer ptr(new MyClass(50));
                  ptr.reset(); // 原对象被删除(输出 "MyClass destroyed"),ptr 变为 nullptr
                  ptr.reset(new MyClass(60)); // 接管新对象(输出 "MyClass constructed")

                  4. 判断有效性

                  • isNull()/ isEmpty():判断是否为空(无对象)。
                  • operator bool():隐式转换为 bool(非空时为 true)。
                  QSharedPointer ptr;
                  if (ptr.isNull()) { 
                      qDebug() << "ptr is null";
                  }
                  
                  if (ptr) { // 等价于 !ptr.isNull()
                      qDebug() << "ptr is not null";
                  }

                  5. 获取原始指针

                  data()get():返回原始指针(谨慎使用,避免外部手动 delete)。

                  MyClass* rawPtr = ptr.data();
                  rawPtr->value = 100; // 直接修改对象(不推荐,破坏封装)

                  三、高级用法

                  1. 自定义删除器(Deleter)

                  默认情况下,QSharedPointer 使用 delete释放对象。若对象通过其他方式分配(如 mallocfopen打开的文件),可自定义删除器。

                  示例:管理 FILE资源*

                  #include 
                  
                  // 自定义删除器:关闭文件
                  void fileCloser(FILE* fp) {
                      if (fp) fclose(fp);
                      qDebug() << "File closed";
                  }
                  
                  int main() {
                      // 用 lambda 作为删除器(更灵活)
                      QSharedPointer filePtr(fopen("test.txt", "r"), [](FILE* fp) {
                          if (fp) fclose(fp);
                          qDebug() << "Custom deleter: File closed";
                      });
                      
                      if (filePtr) {
                          char buf[100];
                          fgets(buf, sizeof(buf), filePtr.data());
                          qDebug() << "Read:" << buf;
                      }
                      // 离开作用域时,filePtr 析构,调用自定义删除器关闭文件
                      return 0;
                  }

                  2. 与 QWeakPointer 配合(解决循环引用)

                  当两个对象互相持有 QSharedPointer 时,会导致循环引用(引用计数无法归零,内存泄漏)。此时需用 QWeakPointer 打破循环(弱引用不增加强引用计数)。

                  示例:循环引用问题

                  class B;
                  
                  class A {
                  public:
                      QSharedPointer bPtr;
                      ~A() { qDebug() << "A destroyed"; }
                  };
                  
                  class B {
                  public:
                      QSharedPointer aPtr; // 循环引用!A 和 B 互相强引用
                      ~B() { qDebug() << "B destroyed"; }
                  };
                  
                  int main() {
                      QSharedPointer a(new A);
                      QSharedPointer b(new B);
                      a->bPtr = b; // a 强引用 b(b 的引用计数=2)
                      b->aPtr = a; // b 强引用 a(a 的引用计数=2)
                      // 离开作用域时,a 和 b 的引用计数各减1(变为1),不会触发析构!
                      return 0;
                  }
                  // 输出:(无析构信息,内存泄漏)

                  解决方案:用 QWeakPointer 替代一方的强引用

                  class B;
                  
                  class A {
                  public:
                      QSharedPointer bPtr;
                      ~A() { qDebug() << "A destroyed"; }
                  };
                  
                  class B {
                  public:
                      QWeakPointer aPtr; // 弱引用,不增加 a 的强引用计数
                      ~B() { qDebug() << "B destroyed"; }
                  };
                  
                  int main() {
                      QSharedPointer a(new A);
                      QSharedPointer b(new B);
                      a->bPtr = b; // b 的引用计数=2(a->bPtr 和 b 本身)
                      b->aPtr = a; // a 的引用计数仍为1(仅 a 本身)
                      
                      // 离开作用域时:
                      // a 析构 → a 的引用计数-1(变为0)→ 调用 A 的析构 → a->bPtr 析构 → b 的引用计数-1(变为1)
                      // b 析构 → b 的引用计数-1(变为0)→ 调用 B 的析构 → b->aPtr 是弱引用,无影响
                      return 0;
                  }
                  // 输出:
                  // A destroyed
                  // B destroyed

                  四、注意事项

                  避免混合管理:不要用多个独立智能指针(如 QSharedPointer 和 std::shared_ptr)管理同一原始指针,会导致重复释放。

                  线程安全:QSharedPointer 的引用计数操作是线程安全的(原子操作),但对象本身的访问仍需同步(如多线程读写对象成员)。

                  与 QObject 的配合:QObject 自带父子内存管理机制(deleteLater),若用 QSharedPointer 管理 QObject 派生类,需注意:

                  • 避免同时设置父对象和 QSharedPointer(可能导致双重释放)。
                  • 推荐用 QSharedPointer 管理无父对象的 QObject,或用 QObject::setParent(nullptr)解除父子关系。

                  不支持数组:QSharedPointer 默认用 delete释放对象,若需管理数组(new T[]),应使用 QSharedPointer(Qt 5.6+),它会调用 delete[]

                  五、总结

                  QSharedPointer 是 Qt 中管理动态对象的核心工具,通过引用计数自动释放资源,适合多模块共享对象的场景。关键要点:

                  • 优先用 QSharedPointer::create()构造,避免原始指针暴露。
                  • 复杂资源管理用自定义删除器
                  • 循环引用用 QWeakPointer​ 解决。
                  • 注意线程安全和与 QObject 的配合。

                  到此这篇关于Qt QSharedPointer用法使用小结的文章就介绍到这了,更多相关Qt QSharedPointer用法内容请搜索北冥有鱼【www.ufcn.cn】以前的文章或继续浏览下面的相关文章希望大家以后多多支持北冥有鱼【www.ufcn.cn】!

                  您可能感兴趣的文章:

                  • Qt中QRadioButton控件的用法详解和实战指南
                  • Qt输入类控件用法超详细讲解
                  • Qt中connect()函数及用法详解
                  • Qt中正则表达式的常见用法(QRegularExpression类)
                  • QT中几种常用的排序函数用法总结
                  • Qt 智能指针QScopedPoint用法小结
                  • Qt QStandardItemModel用法小结
                  本文地址:https://www.ufcn.cn/article/2431069.html

                  如非特殊说明,本站内容均来自于网友自主分享,概不代表本站观点,如有任何问题我们都将在收到反馈后的第一时间进行处理!

                  • Linux-getopt命令用法及说明
                    07月 09 2026

                    这篇文章主要介绍了Linux-getopt命令用法及说明,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教 目录简介格式说明要点使用总结简介 getopt命令可以接受一系列任意形式的命令行选项和参数,并自动将它们转换成适当的格式。 格式说明 getopt三种使用方式 # 第一种:无法处理带有空格的参数 getopt optstring parameters # 第二种...

                  • 深入理解Qt Q_OBJECT宏
                    07月 09 2026

                    在Qt开发中,Q_OBJECT不仅仅是一个宏,它是连接C++ 静态世界与Qt动态元对象系统的桥梁,本文就来详细的介绍一下Q_OBJECT宏的使用,感兴趣的可以了解一下 目录1. 核心作用:启用 Qt 的元对象系统 (Meta-Object System)2. 具体功能详解A. 信号与槽 (Signals & Slots) - 最核心功能B. 运行时类型信息 (RTTI) 增强C. 动态属性...

                  • Qt使用Qt Linguist 实现多语言切换
                    07月 09 2026

                    本文主要介绍了Qt使用Qt Linguist 实现多语言切换,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧 目录前言一、Qt 国际化工作流程二、项目配置1. .pro 文件配置2. 创建资源文件 resources.qrc三、界面设计mainwindow.ui四、头文件 mainwindow.h五、源文件 mainwindow...

                  • Qt的环境变量QT_QPA_PLATFORM的使用
                    07月 09 2026

                    本文主要介绍了Qt的环境变量QT_QPA_PLATFORM的使用,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧 目录一、QPA架构与QT_QPA_PLATFORM的核心作用​​二、常见平台插件1. ​​eglfs​​(Embedded GL Full Screen)2. ​​linuxfb​​(Linux Framebuffe...

                  • Qt QRegularExpression正则类的使用小结
                    07月 09 2026

                    本文主要介绍了Qt QRegularExpression正则类的使用小结,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧 目录1. 为什么要用 QRegularExpression?(历史背景)2. 核心类结构3. 基础用法:匹配与捕获3.1 简单匹配3.2 捕获组 (Capture Groups)4. 高级特性4.1 贪婪与非...

                  • SQL中的CASE WHEN用法实例详解
                    07月 07 2026

                    SQL中的CASE WHEN是核心条件表达式,功能类似编程中的 if-else 或 switch,用于在查询中实现逻辑判断、数据分类及动态计算,本文介绍SQL中的CASE WHEN用法,感兴趣的朋友一起看看吧 目录一、简单CASE WHEN函数:二、CASE WHEN条件表达式函数三、常用场景场景1:不同状态展示为不同的值场景2:统计不同状态下的值场景3:配合聚合函数做统计场景4:CASE WHE...

                  • c++ std::Any 用法小结
                    07月 07 2026

                    本文演示了C++17中std::any的用法测试,示例代码展示了std::any可以存储多种类型值,通过any_cast进行类型安全的值提取,下面就来详细的介绍一下,感兴趣的可以了解一下 据说std::Any能存任意值,测试下: Test1.h: #pragma once void testAny(void); Test1.cpp: #include "Test1.h" #include #inc...

                  • 迷你世界工具大全用法2026
                    07月 07 2026

                    迷你世界里面有很多的道具物品,今天给大家带来了游戏里面的最新版本的工具大全用法,还有小伙伴不清楚游戏里面的工具怎么用,那么下面就是具体的内容. 迷你世界工具大全用法 氧气面罩 属性:工具 解锁途径:无需解锁 需要材料 棉花*2 雀莺羽毛*1 合成台 工具箱 用途:使用雀莺的羽毛制成的密封性极好的面罩,是星球旅行的必备装。装备到头部可以抵御外星恶劣的缺氧环境,装备会扣除耐久度,耐久度为0时装备会消失...

                  • 跃问怎么写申论 跃问公考申论辅导用法
                    07月 03 2026

                    申论写作需紧扣问题、原因、对策,跃问公考辅导聚焦阅卷得分点。使用前须完成三件事:下载真题包、研读评分细则、圈画材料关键信息;批改功能需规范上传或输入,并先做基础测试;范文库可提取并替换高分句式。 ☞☞☞AI 智能聊天, 问答助手, AI 智能搜索, 多模态理解力帮你轻松跨越从0到1的创作门槛☜☜☜ 申论写作不是堆砌漂亮话,而是用规范语言把问题、原因、对策说清楚,跃问公考的申论辅导材料正是围绕这个核...

                  • MySQL中REPLACE函数的用法与实战案例详解
                    07月 03 2026

                    本文详细解析了MySQL中的REPLACE函数,包括其基础语法、核心特性及常见使用场景,REPLACE函数通过全局匹配方式替换字符串内容,适合处理固定文本清理任务,感兴趣的小伙伴可以了解下 目录一、前言二、函数基础语法三、基础使用示例四、业务实战:接口日志提取URL参数五、REPLACE 与 SUBSTR 性能深度对比(重点)六、高频踩坑总结七、拓展:REPLACE的两种使用场景八、REPLACE...