【Qt】Qt中智能指针

2023-11-01

一、QPointer

QPointer是一个被保护的指针,行为类似于普通的c++指针T *,会在被引用的对象被销毁时自动清除(不像普通的C++指针,在这种情况下会成为“悬空指针”)。但是,T必须是QObject的子类,否则将导致编译失败或链接错误。

当需要存储一个指向其他地方(可能是类或者他人需要修改的指针)拥有的QObject的指针时,这时使用保护指针非常合适,如果此时程序中仍然持有该内存区域的引用时,该指针区域可能会在其他的地方被销毁。那么使用保护指针可以安全地测试指针的有效性,从而避免使用无效的、非法的或者悬空指针。如下代码:

	QPointer<QLabel> label = new QLabel;
	label->setText("&Status:");
	...
    if (label)
        label->show();

​ 如果QLabel在此期间被删除,label变量将保存nullptr而不是一个无效的地址,最后一行将永远不会执行。

​ 除了指针【算术操作符】(+、-、++和–)之外,QPointer可用函数和操作符与普通无保护指针的函数和操作符相同,但是这些操作符通常只使用在对象数组上。

二、QSharedPointer

(在Qt 4.5 版本中引入,该智能指针在开发中较为常用)

​ QSharedPointer是一个引用计数的共享指针对象的实现,可以用来维护对单个指针的引用集合。

​ QSharedPointer在c++中是一个自动、共享的指针。它的行为与普通的指针完全一样,包括对const的支持行为。

​ QSharedPointer对象可以从普通指针、另一个QSharedPointer对象创建,也可以通过将QWeakPointer对象提升为强引用创建。

​ QSharedPointer和QWeakPointer是可重入类。通常一个给定的QSharedPointer或QWeakPointer对象不能被多个线程在没有同步的情况下同时访问。

​ 不同的QSharedPointer和QWeakPointer对象可以被多个线程在同一时间安全地访问。这包括它们持有指向同一对象的指针的情况;引用计数机制是原子的,不需要手动同步。

​ QSharedPointer 是线程安全的,因此即使有多个线程同时修改 QSharedPointer 对象也不需要加锁。这里要特别说明一下,虽然 QSharedPointer 是线程安全的,但是 QSharedPointer 指向的内存区域可不一定是线程安全的。所以多个线程同时修改 QSharedPointer 指向的数据时还要应该考虑加锁的。

2-1、常用操作函数

1)、返回此对象所引用的指针的值
T *QSharedPointer::data() const
    
注意:不要删除这个函数返回的指针,也不要将它传递给其他可能删除它的函数,包括创建QSharedPointer或QWeakPointer对象。
2)、清除这个QSharedPointer对象,删除它可能对该指针的引用。如果这是最后一个引用,那么指针本身将被删除。
void QSharedPointer::clear()
3)、重置reset

Qt 5.0 版本以上引入

void QSharedPointer::reset(T **t*)

将QSharedPointer对象重置为指向t。

4)、强制类型转换
(4-1)constCast()

​ 将该指针的类型进行const_cast转换为X,并返回共享该引用的QSharedPointer。此函数可用于向上和向下类型转换,但对于向上类型转换更有用。

(4-2)dynamicCast()

​ 执行从该指针的类型到X的动态转换,并返回一个共享引用的QSharedPointer。如果这个函数被用于向上转换,那么QSharedPointer将执行dynamic_cast,这意味着如果QSharedPointer指向的对象不是X类型,那么返回的对象将是空的。

​ 特别说明:模板类型X必须具有与该对象的模板相同的const和volatile限定符,否则强制转换将失败。如果需要删除这些限定符,需使用constCast()。

(4-3)staticCast()

​ 执行从该指针的类型到X的静态转换,并返回一个共享该引用的QSharedPointer。此函数可用于向上和向下类型转换,但对于向上类型转换更有用。

​ 注意:模板类型X必须具有与该对象的模板相同的const和volatile限定符,否则强制转换将失败。如果需要删除这些限定符,请使用constCast(),这一点和dynamicCast()一样。

(4-4)objectCast()

​ 从该指针的类型执行qobject_cast()到X,并返回共享该引用的QSharedPointer。如果这个函数被用于向上转换,那么QSharedPointer将执行qobject_cast,这意味着如果QSharedPointer指向的对象不是X类型,那么返回的对象将是空的。


三、QScopedPointer

​ 类似于 C++ 11 中的 unique_ptr。当内存数据只在一处被使用,用完就可以安全的释放时就可以使用 QScopedPointer。

​ QScopedPointer只是持有一个指向堆分配对象的指针,并在其析构函数中删除它。当一个对象需要分配和删除堆时,这个类很有用,但仅此而已。QScopedPointer是轻量级的,它不使用额外的结构或引用计数。

​ 例如这样一个运用场景:在函数体中创建了一个堆分配的内存,然后进行一系列操作和使用,最后在本函数体中将释放该堆空间。如下代码片段

void myFunction(bool useSubClass)
{
    // assuming that MyClass has a virtual destructor
    QScopedPointer<MyClass> p(useSubClass ? new MyClass() : new MySubClass);
    QScopedPointer<QIODevice> device(handsOverOwnership());

    if (m_value > 3)
        return;

    process(device);
}

​ 【注意事项】

​ 使用delete的代码是使用QScopedPointer的候选者(如果不是,可能是另一种类型的智能指针,如QSharedPointer)

四、QWeakPointer

​ 此类使用较少

​ QWeakPointer是C++中对指针的自动弱引用。它不能用于直接解引用指针,但可以用于验证指针是否在另一个上下文中被删除。

​ QWeakPointer对象只能通过QSharedPointer赋值来创建。

​ 值得注意的是,QWeakPointer没有提供自动强制转换操作符来防止错误的发生。即使QWeakPointer跟踪一个指针,它也不应该被视为指针本身,因为它不能保证所指向的对象仍然有效。

​ 因此,要访问QWeakPointer正在跟踪的指针,必须首先将其提升为QSharedPointer,并验证结果对象是否为空。

五、QSharedDataPointer

​ QSharedDataPointer 这个类帮我们实现数据的隐式共享。Qt 中大量的采用了隐式共享写时拷贝技术。比如下面这个例子:

QString str1 = "iriczhao";
QString str2 = str1;
QString str2[2] = 'y';

​ 第二行执行完后,str2 和 str1 指向的同一片内存数据。当第三句执行时,Qt 会为 str2 的内部数据重新分配内存。这样做的好处是可以有效的减少大片数据拷贝的次数,提高程序运行效率。

​ QSharedDataPointer持有一个指向共享数据的指针(即,从QSharedData派生的类)。它通过放置在QSharedData基类中的内部引用计数来实现这一点。因此,这个类可以根据对被保护的数据的访问类型进行分离:如果是非const访问,它会自动创建一个副本以完成操作。

六、QScopedArrayPointer

​ 如果我们指向的内存数据是一个数组,这时可以用 QScopedArrayPointer。QScopedArrayPointer 与 QScopedPointer 类似,用于简单的场景。

​ 例如:

void foo()
{
     QScopedArrayPointer<int> i(new int[10]);
     i[2] = 42;
     ...
     return; // our integer array is now deleted using delete[]
}

搜索/关注【嵌入式小生】vx公众号,获取更多精彩内容>>>>
请添加图片描述

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

【Qt】Qt中智能指针 的相关文章

  • 在C语言中使用“void”

    我很困惑为什么我们需要通过void转换为 C 函数 int f void return 0 versus int f return 0 什么是正确的做法以及为什么 In C int f 是一种老式的声明 它说f需要固定但未指定数量和类型的参
  • 查找哪些页面不再与写入时复制共享

    假设我在 Linux 中有一个进程 我从中fork 另一个相同的过程 后forking 因为原始进程将开始写入内存 Linux写时复制机制将为进程提供与分叉进程使用的不同的唯一物理内存页 在执行的某个时刻 我如何知道原始进程的哪些页面已被写
  • 为什么libc++的shared_ptr实现使用完整内存屏障而不是宽松内存屏障?

    在boost的实现中shared ptr 它用放松内存排序以增加其引用计数 https github com boostorg smart ptr blob master include boost smart ptr detail sp
  • OpenCv读/写视频色差

    我试图简单地使用 openCV 打开视频 处理帧并将处理后的帧写入新的视频文件 我的问题是 即使我根本不处理帧 只是打开视频 使用 VideoCapture 读取帧并使用 VideoWriter 将它们写入新文件 输出文件看起来比输入更 绿
  • C++:重写已弃用的虚拟方法时出现弃用警告

    我有一个纯虚拟类 它有一个纯虚拟方法 应该是const 但不幸的是不是 该接口位于库中 并且该类由单独项目中的其他几个类继承 我正在尝试使用这个方法const不会破坏兼容性 至少在一段时间内 但我找不到在非常量方法重载时产生警告的方法 以下
  • C++ 异步线程同时运行

    我是 C 11 中线程的新手 我有两个线程 我想让它们同时启动 我可以想到两种方法 如下 然而 似乎它们都没有按照我的预期工作 他们在启动另一个线程之前启动一个线程 任何提示将不胜感激 另一个问题是我正在研究线程队列 所以我会有两个消费者和
  • 从多个类访问串行端口

    我正在尝试使用串行端口在 arduino 和 C 程序之间进行通信 我对 C 编程有点陌生 该程序有多种用户控制形式 每一个都需要访问串口来发送数据 我需要做的就是从每个类的主窗体中写入串行端口 我了解如何设置和写入串行端口 这是我的 Fo
  • 访问者和模板化虚拟方法

    在一个典型的实现中Visitor模式 该类必须考虑基类的所有变体 后代 在许多情况下 访问者中的相同方法内容应用于不同的方法 在这种情况下 模板化的虚拟方法是理想的选择 但目前这是不允许的 那么 模板化方法可以用来解析父类的虚方法吗 鉴于
  • 如何从 C# 控制器重定向到外部 url

    我使用 C 控制器作为网络服务 在其中我想将用户重定向到外部网址 我该怎么做 Tried System Web HttpContext Current Response Redirect 但没有成功 使用控制器的重定向 http msdn
  • C 语言中 =+(等于加)是什么意思?

    我碰到 与标准相反 今天在一些 C 代码中 我不太确定这里发生了什么 我在文档中也找不到它 In ancientC 版本 相当于 它的残余物与最早的恐龙骨头一起被发现 例如 B 引入了广义赋值运算符 使用x y to add y to x
  • 即使手动设置显示环境变量后,WSL Ubuntu 也会显示“错误:无法打开显示”

    我在 WSL Ubuntu 上使用 g 我使用 git 克隆了 GLFW 存储库 使用了ccmake命令配置并生成二进制文件 然后使用make在 build 目录中最终创建 a文件 我安装了所有OpenGL相关的库 usr ld 我不记得我
  • 如何在c#中的内部类中访问外部类的变量[重复]

    这个问题在这里已经有答案了 我有两个类 我需要声明两个类共有的变量 如果是嵌套类 我需要访问内部类中的外部类变量 请给我一个更好的方法来在 C 中做到这一点 示例代码 Class A int a Class B Need to access
  • 在 C 中使用 GNU automake 中的解析器

    我是 GNU autotools 的新手 在我的项目中使用了 lex 和 yacc 解析器 将它们作为 makefile am 中的源代码会产生以下错误 配置 in AC CHECK PROGS YACC bison yacc none i
  • 将代码拆分为标头/源文件

    我从 Asio 的示例页面中获取了以下代码 class tcp connection public boost enable shared from this
  • 运算符“==”不能应用于“int”和“string”类型的操作数

    我正在编写一个程序 我想到了一个数字 然后计算机猜测了它 我一边尝试一边测试它 但我不断收到不应该出现的错误 错误是主题标题 我使用 Int Parse 来转换我的字符串 但我不知道为什么会收到错误 我知道它说 不能与整数一起使用 但我在网
  • 我在在线程序挑战编译器中遇到演示错误

    include
  • 使用 C# 从 DateTime 获取日期

    愚蠢的问题 给定日期时间中的日期 我知道它是星期二 例如我如何知道它的 tue 2 和 mon 1 等 Thanks 您正在寻找星期几 http msdn microsoft com en us library system datetim
  • 双精度类型二维多维数组的 pinvoke 编组作为 c# 和 c++ 之间的输入和输出

    我有以下我正在尝试解决的双物质类型的 2d 多维数组的 c 和 c pinvoke 编组 我已经查看了以下热门内容以获得我目前拥有的内容使用双精度数组进行 P Invoke 在 C 和 C 之间编组数据 https stackoverflo
  • 用于 C# XNA 的 Javascript(或类似)游戏脚本

    最近我准备用 XNA C 开发另一个游戏 上次我在 XNA C 中开发游戏时 遇到了必须向游戏中添加地图和可自定义数据的问题 每次我想添加新内容或更改游戏角色的某些值或其他内容时 我都必须重建整个游戏或其他内容 这可能需要相当长的时间 有没
  • 匿名结构体作为返回类型

    下面的代码编译得很好VC 19 00 23506 http rextester com GMUP11493 标志 Wall WX Za 与VC 19 10 25109 0 标志 Wall WX Za permissive 这可以在以下位置检

随机推荐

  • android mtk分析,MTK android平台LCD 驱动的代码分析与讲解

    http blog csdn net sunweizhong1024 article details 8447915 MTK LCD Driver 代码的路是在 mediatek source kernel driver vedio mtk
  • static、const、volatile

    4 关键字static的作用是什么 解答 在C语言中 关键字static有三个明显的作用 在函数体中 一个被声明为静态的变量在这一函数被调用过程中只会被分配一次内存 且整个运行期间不会重新分配 在函数体外 某个源文件内 一个被声明为静态的变
  • BSP概念总结

    嵌入式计算机系统主要由硬件层 中间层 系统软件层和应用软件层四层组成 硬件层 包含CPU 存储器 SDRAM ROM Flash等 通用设备接口和 I O接口 A D D A I O等 其中操作系统和应用程序都可以固化在ROM中 中间层 硬
  • DVWA stored 中级

    跟reflected没啥区别 大写绕过
  • 【 C++ 】函数模板进阶

    目录 1 非类型模板参数 2 模板的特化 2 1 概念 2 2 函数模板特化 2 3 类模板特化 全特化 偏特化 类模板特化示例 3 总结 1 非类型模板参数 模板参数分类类型形参与非类型形参 类型模板参数 出现在模板参数列表中 跟在cla
  • Code Llama: Open Foundation Models for Code

    本文是LLM系列文章 针对 Code Llama Open Foundation Models for Code 的翻译 Code Llama 代码的开放基础模型 摘要 1 引言 2 Code Llama 专业化Llama2用于代码 3 结
  • 虚拟机VMware安装Ubuntu20.04

    文章目录 前言 一 下载安装VMware 虚拟机和系统镜像 二 安装系统 三 更换阿里软件源 前言 使用虚拟机安装Ubuntu20 04 并对环境进行简单配置 一 下载安装VMware 虚拟机和系统镜像 官网下载虚拟机 Ubuntu20 0
  • 将硬盘转换成GPT分区格式

    首先你要知道并非只有更换成这种格式才能安装WIN10这样的新系统 只有在硬盘容量为3TB以上 而你又想往上面装操作系统时 才会涉及到GPT分区 若是往小于2 2TB的硬盘上装系统 则无须使用GPT格式 使用MBR分区 照样可以正常使用WIN
  • Py的docx库:Python操作docx文件的详细教程

    Py的docx库 Python操作docx文件的详细教程 docx库是一种Python库 它使得在Python中提取 编辑和创建Microsoft Word 2007 docx文件变得容易 这个库具有非常强大的功能 可以处理Word文档中的
  • php连接mysql数据库报No such file or directory错误

    mysql connect 连接数据库时报No such file or directory错误 原因是mac下的默认php ini配置default socket 在 var mysql mysql socket 而后安装的mysql的s
  • 计算机 游戏 排名2015年,2015十大高性能游戏笔记本电脑排行 最强游戏本推荐

    电脑游戏拥有千万玩家 在全球市场实际上比游戏主机更受欢迎 当然 工欲善其事必先利其器 一台高性能PC是快乐游戏的基础 一些拥有较好电脑知识 善于动手的用户可以选择自行DIY一台台式游戏PC 但这显然不适合所有人 所以 高性能游戏笔记本也成为
  • 一个男人的自白

    十岁以前 就不说了 无非是淘气和不懂事 十三四岁的时候 开始对女孩有好感 但是却离女孩远远的 并且以讨厌女孩自居 十五岁的时候 听别人说某某把女朋友甩了 女孩自杀了 他想 自己将来一定要做个痴情的男人 一生只爱一个人 十六岁的时候 他喜欢上
  • 数据库的死锁问题在设计期就可以避免

    前几天偶尔与一位数据库工程师谈起数据库的死锁 deadlock 问题 根据以往的经验 我一直认为 1 MSSQL DB2 Oracle之类的现代DBMS或者中间件可以帮助我们自动解决绝大部分死锁 其余一部分难以处理的死锁则由DBA在数据库控
  • Leetcode--无重复字符的最长子串(思路+解题逻辑+详细代码注释)

    题目 给定一个字符串 s 请你找出其中不含有重复字符的 最长子串 的长度 示例 1 输入 s abcabcbb 输出 3 解释 因为无重复字符的最长子串是 abc 所以其长度为 3 示例 2 输入 s pwwkew 输出 3 解释 因为无重
  • 02 - MATLAB基础

    目录 一 matlab系统环境 二 MATLAB数值数据 二 变量与赋值 四 MATLAB矩阵的表示 五 矩阵元素的引用 六 MATLAB基本运算 七 字符串处理 注 2 6节为数值型数据 第7节为字符型数据 一 matlab系统环境 1
  • YOLO V5 使用

    目录 前言 环境 1 安装python所需的数据库 2 采集图片样本 2 1勾选View内容 2 2切换至YOLO模式 2 3打开训练图集文件以及labels文件 2 4建立类名 2 5开始标记 3 训练模型 4 模型预测 5 预测结果的返
  • Flutter 1-10】Flutter手把手教程Dart语言——运算符

    作者 弗拉德 来源 弗拉德 公众号 fulade me 运算符 运算符是一种告诉编译器执行特定的数学或逻辑操作的符号 Dart语言内置了丰富的运算符 并提供了以下类型的运算符 算术运算符 关系运算符 类型判断运算符 赋值运算符 逻辑运算符
  • 什么浏览器好用_手机浏览器不只UC,好用的浏览器还有这些

    在手机上 很多人都用UC 当然也有不少人使用的是系统预装的浏览器 其实除了这两种之外 还有很多良心浏览器你没见过 今天就给大家介绍下五款安卓平台上那些比较良心而且相对好用的浏览器 一 X浏览器 这个浏览器非常小 仅800K左右 也不需要很多
  • java 手机号运营商号段正则匹配(长期更新)

    import com cq mysmscommon enums SpTypeEn import java util regex Pattern public class MobileOperator 中国移动号码正则 139 138 137
  • 【Qt】Qt中智能指针

    文章目录 一 QPointer 二 QSharedPointer 2 1 常用操作函数 1 返回此对象所引用的指针的值 2 清除这个QSharedPointer对象 删除它可能对该指针的引用 如果这是最后一个引用 那么指针本身将被删除 3