Qt 智能指针介绍: QSharedPointer、QWeakPointer 、QScopedPointer 、QPointer(附实例)

2023-05-16

文章目录

  • 1. 概述
  • 2. Qt 中有几种智能指针?
    • 2.1 QSharedPointer 实例
    • 2.2 QSharedPointer 与 QWeakPointer 实例
    • 2.3 QScopedPointer 实例
    • 2.4 QPointer 实例

1. 概述

在使用动态内存分配的情况下,需要确保对象的所有权正确地被管理和转移。使用智能指针可以帮助我们自动管理对象的生命周期和所有权,避免内存泄漏和悬挂指针的问题。

♦ 什么时候需要用到智能指针?

  • 在使用QObject对象的情况下,需要确保对象的生命周期和父子关系正确地被管理。QObject对象的生命周期受到父子关系的影响,因此需要使用QPointer等智能指针来管理QObject对象的指针。

  • 多线程编程中,需要确保多个线程访问共享对象时不会发生竞态条件。使用智能指针可以避免竞态条件的发生,因为它会自动对对象进行引用计数,确保在所有引用都被释放后才会删除对象

  • 在使用异常处理时,需要确保在函数返回时所有动态分配的对象都被正确地删除。使用智能指针可以确保在函数返回时所有动态分配的对象都被正确地删除,以避免内存泄漏。

  • 防止忘记调用 delete

总之,当我们需要动态分配内存并且需要确保对象的生命周期、所有权、线程安全性等方面的正确管理时,就可以考虑使用智能指针。

2. Qt 中有几种智能指针?

常用的包括 QSharedPointer、QWeakPointer、QScopedPointer和QPointer;

  • QSharedPointer 适用于共享所有权的情况
  • QWeakPointer 适用于不共享所有权但需要访问QSharedPointer所管理的对象的情况
  • QScopedPointer 适用于独占所有权的情况。
  • QPointer 主要用于解决指针的空悬问题,适用于Qt对象之间的引用

    具体介绍如下:

2.1 QSharedPointer 实例

QSharedPointer:强引用,大体相当于C++11 标准中的 shared_ptr, 用于管理动态分配的对象的共享所有权,即多个QSharedPointer对象可以指向同一个对象,并共享该对象的内存管理。

它使用引用计数来追踪对象的使用情况,当最后一个QSharedPointer对象被销毁时,它将自动释放对象的内存。由于使用了引用计数,QSharedPointer能够自动处理指针的生命周期,避免内存泄漏和空悬指针等问题,因此是Qt中最常用的智能指针。

#include <QCoreApplication>
#include <QSharedPointer>
#include <QDebug>

class MyClass
{
public:
    MyClass(int value) : m_value(value) {}
    void setValue(int value) { m_value = value; }
    int getValue() const { return m_value; }
private:
    int m_value;
};

int main()
{
    QSharedPointer<MyClass> pointer1(new MyClass(10));  // 引用计数为1
    {
        QSharedPointer<MyClass> pointer2 = pointer1;    // 引用计数为2
    }                                                   // pointer2销毁,引用计数为1
    qDebug() << "Value:" << pointer1->getValue();       // 输出10
    {
        QSharedPointer<MyClass> pointer3 = pointer1;    // 引用计数为2
        
        pointer1.clear();                               // 引用计数为1
        qDebug() << "Value:" << pointer3->getValue();   // 输出10
        
		QWeakPointer<MyClass> weak(pointer3);
    }                                                   // pointer3销毁,引用计数为0,MyClass对象被自动释放
    return 0;
}

输出结果:
在这里插入图片描述

需要注意的是,QSharedPointer只能管理动态分配的对象的内存。如果我们将其用于指向栈对象或全局对象,那么它就不会自动释放对象的内存,这可能会导致程序崩溃或内存泄漏。

深入了解:C++ 智能指针(shared_ptr/weak_ptr)源码分析

2.2 QSharedPointer 与 QWeakPointer 实例

QWeakPointer:弱引用,大体相当于C++11 标准中的 weak_ptr ,用于在不共享所有权的情况下访问QSharedPointer指向的对象。QWeakPointer指向QSharedPointer所管理的对象,但不会增加对象的引用计数,也不会影响对象的生命周期。当对象被释放时,QWeakPointer会自动被置为空指针,避免了空悬指针的问题。

QWeakPointer 是为配合 QSharedPointer 而引入的一种智能指针,它更像是 QSharedPointer 的一个助手,像一个旁观者一样来观测资源的使用情况。

#include <QSharedPointer>
#include <QWeakPointer>
#include <QDebug>

class MyClass
{
public:
    MyClass(int value) : m_value(value) {
        qDebug() << "MyClass constructor called with value" << m_value;
    }
    ~MyClass() {
        qDebug() << "MyClass destructor called with value" << m_value;
    }
    int getValue() const {
        return m_value;
    }

private:
    int m_value;
};

int main()
{
    QSharedPointer<MyClass> shared(new MyClass(20));
    QWeakPointer<MyClass> weak(shared);

    qDebug() << "Shared pointer value:" << shared->getValue();
    qDebug() << "Weak pointer value:" << weak.data()->getValue();

    shared.clear();

    if (weak.isNull()) {
        qDebug() << "Weak pointer is null - object has been deleted"; //执行
    } else {
        qDebug() << "Weak pointer is not null - object still exists";
    }

    return 0;
}

打印结果:

在这里插入图片描述
例中 创建了一个QSharedPointer对象和一个QWeakPointer对象,它们都指向一个MyClass对象。在main函数的结尾处,使用 shared.clear() 来释放 MyClass 对象的所有权。此时,MyClass对象的引用计数为0,将被自动删除,而此时 QWeakPointer 对象 weak 也为null。

实际使用过程中可以再封装一下:

typedef QSharedPointer<MyClass>  SharedMyClassPtr;
typedef QWeakPointer<MyClass>    WeakMyClassPtr;

2.3 QScopedPointer 实例

QScopedPointer 类似于 C++ 11 中的 unique_ptr 用于管理动态分配的对象的独占所有权,即同一时间只能有一个QScopedPointer指向该对象。

QScopedPointer使用了RAII(资源获取即初始化)技术,当QScopedPointer被销毁时,它将自动释放所管理的对象的内存。QScopedPointer不支持拷贝和赋值操作,这是为了避免在多个指针之间共享所有权的问题。如果需要在多个指针之间转移所有权,应该使用QSharedPointer或QWeakPointer。

如下简单示例:

#include <QScopedPointer>
#include <QDebug>

class MyClass
{
public:
    MyClass(int value) : m_value(value) {
        qDebug() << "MyClass constructor called with value" << m_value;
    }
    ~MyClass() {
        qDebug() << "MyClass destructor called with value" << m_value;
    }
    int getValue() const {
        return m_value;
    }

private:
    int m_value;
};

int main()
{
    QScopedPointer<MyClass> myObject(new MyClass(23));

    qDebug() << "My object value:" << myObject->getValue();

    return 0;
}

结果如下:

在这里插入图片描述

2.4 QPointer 实例

由于QObject对象的生命周期受到父子关系的影响,当父对象被删除时,所有子对象也会被删除。使用 QPointer 可以避免在父对象被删除时,子对象的指针指向已经被删除的对象的问题。

通常情况下,我们在手动delete一个指针的时候,需要再将其置空,要不然会变成一个悬挂的野指针,那么QPointer就是帮忙干这事的,会在对象被销毁时,自动设置为NULL

♦ 场景一:

//
// myqpointer.cpp
//
#include "myqpointer.h"

MyQPointer::MyQPointer(QObject *parent) : QObject(parent)
{
    qDebug() << "MyObject constructor called";
}

MyQPointer::~MyQPointer()
{
    qDebug() << "MyObject destructor called";
}

void MyQPointer::doSomething()
{
    qDebug() << "MyObject is doing something";
}

//
// myqpointer.h
//
#ifndef MYQPOINTER_H
#define MYQPOINTER_H

#include <QObject>
#include <QPointer>
#include <QDebug>

class MyQPointer : public QObject
{
    Q_OBJECT
public:
    explicit MyQPointer(QObject *parent = nullptr);
    ~MyQPointer();
    void doSomething();
};
#endif // MYQPOINTER_H

//
// main.cpp
//
#include <QCoreApplication>
#include "myqpointer.h"

int main(int argc, char *argv[])
{

    QCoreApplication a(argc, argv);

     MyQPointer* myQPointer = new MyQPointer();

    delete myQPointer;
//    myQPointer = nullptr;

    if (myQPointer) {
        qDebug() << "\nMyObject is valid";
        myQPointer->doSomething();
    } else {
        qDebug() << "\nMyObject is null";
    }

    return a.exec();
}

运行结果:
在这里插入图片描述
delete pLabel; 过后如果不手动置空,这里输出将是 “MyObject is valid”。

使用智能指针 QPointer,更改下mian.cc:

//
// main.cpp
//
#include <QCoreApplication>
#include "myqpointer.h"

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    QPointer<MyQPointer> myQPointer(new MyQPointer);
    delete myQPointer;
//    myQPointer = nullptr;

    if (myQPointer) {
        qDebug() << "\nMyObject is valid";
        myQPointer->doSomething();
    } else {
        qDebug() << "\nMyObject is null";
    }

    return a.exec();
}

运行结果:

在这里插入图片描述
写法很简单,就是直接将

 MyQPointer* myQPointer = new MyQPointer();

替换成

QPointer<MyQPointer> myQPointer(new MyQPointer);

在main函数的结尾处,我们调用了MyObject对象的deleteLater()函数,将其标记为待删除状态。然后我们再次检查QPointer对象是否为空,此时它应该返回一个空指针

♦ 场景二:

将上述 main.cc 中修改如下:

#include <QCoreApplication>
#include "myqpointer.h"


int main(int argc, char *argv[])
{

    QCoreApplication a(argc, argv);

     MyQPointer* myQPointer1 = new MyQPointer();
     MyQPointer* myQPointer2 = myQPointer1;

    delete myQPointer1;
    myQPointer1 = nullptr;

    if (myQPointer1) {
        qDebug() << "myQPointer1 is valid";
    } else {
        qDebug() << "myQPointer1 is null";
    }
    if (myQPointer2) {
        qDebug() << "myQPointer2 is valid";
    } else {
        qDebug() << "myQPointer2 is null";
    }
    return a.exec();
}

运行结果:

在这里插入图片描述

上面这种情况,myQPointer2 是直接复制myQPointer1,指向同一个地址,这时候delete myQPointer1过后,就不需要再delete myQPointer2 ,否则将会报错,但是 myQPointer2 也需要手动置空,否则变成悬挂的野指针,实际情况中可能经常会忘记置空,甚至将指针delete两次,对于新手来说,这种错误是常犯的。

将上述:

MyQPointer* myQPointer2 = myQPointer1;

修改为:

QPointer<MyQPointer> myQPointer2(myQPointer1);
//QPointer<MyQPointer> myQPointer2 = myQPointer1 ;  //两者都行

运行结果:

在这里插入图片描述

当然最好的方式是,myQPointer1 和 myQPointer2都用智能指针的方式,这样就不用手动置空了。这是 QPointer 最常见的一种使用场景。

♦ 参考:

Qt 中的智能指针

Qt智能指针–QPointer

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

Qt 智能指针介绍: QSharedPointer、QWeakPointer 、QScopedPointer 、QPointer(附实例) 的相关文章

  • TF坐标变换的学习

    官方教程 xff1a http wiki ros org tf ROS中的很多软件包都需要机器人发布tf变换树 xff0c 那么什么是tf变换树呢 xff1f 抽象的来讲 xff0c 一棵tf变换树定义了不同坐标系之间的平移与旋转变换关系
  • Docker 服务端口一览

    最近研究微服务 xff0c 使用Docker来进行部署应用 说实话docker是个好东西 xff0c 只要编写好Dockerfile文件和docker compose yml文件 xff0c 便能快速启动并运行相关服务 调试过程中查看服务可
  • 鱼眼镜头的成像原理到畸变矫正(完整版)

    最近刚接触鱼眼相机 xff0c 发现网上资料还是比较零散的 xff0c 于是把搜罗到的资料汇总梳理了一下 这里推荐大家直接看链接6的论文 xff0c 从成像模型到畸变矫正整个过程讲的比较清楚 xff0c 网上很多版本其实都是根据这两篇论文来
  • STM32通过广和通ADP-L610-Arduino进行TCP/IP通信

    STM32通过广和通L610进行TCP IP通信 一 写在前面 本次参加嵌入式大赛 xff0c 使用了广和通的ADP L610 Arduino板子进行通信 项目要求大概是本地上传数据到服务器 xff0c 服务器接收后发送给客户端 xff0c
  • Visual Studio Code Git版本控制 更改语言成英文

    一 初始化git库 新版vscode只能打开一个文件夹 xff0c 当你打开这个文件夹后 xff0c 再点击左边的git控制按钮 xff0c 就会初始化该文件夹为git工作目录 xff0c 如果已经有git控制 xff0c 则不会改变 在v
  • STM8S003F3 开发环境搭建

    硬件相关 芯片介绍 型号 xff1a STM8S003F3P6 xff0c 用的不是ARM内核 STM32用的是ARM xff0c 而是意法半导体自己生产的高性能8位内核 xff1a STM8AF 主要针对汽车电子应用 xff0c 如 xf
  • 教你写Makefile(很全,含有工作经验的)

    原文 转载文 Makefile 值得一提的是 xff0c 在Makefile中的命令 xff0c 必须要以 Tab 键开始 什么是makefile xff1f 或许很多Winodws的程序员都不知道这个东西 xff0c 因为那些Window
  • 与JWT的不解之缘

    jar xff1a maven lt dependency gt lt groupId gt io jsonwebtoken lt groupId gt lt artifactId gt jjwt lt artifactId gt lt v
  • 连接服务器报错:Key exchange was not finished, connection is closed.

    解决方案 xff1a 在 etc ssh sshd config最后添加如下行内容解决问题 KexAlgorithms diffie hellman group1 sha1 diffie hellman group14 sha1 diffi
  • ros多线程管理

    单线程Spinning ros spin 是最简单的单线程自旋 它会一直调用直到结束 用法 ros spin ros spinOnce 另一个单线程spinning是ros spinOnce 它定期调用等待在那个点上的所有回调 用法 ros
  • (每日一读2019.10.24)一种基于通用优化方法的多传感器全局里程计估计框架(VINS-Fusion)

    参考博文 萌新学VINS Fusion 一 特征跟踪 萌新学VINS Fusion 二 特征跟踪 摘要 精确的状态估计是自主机器人的一个基本问题 为了实现局部精确和全局无漂移状态估计 通常将具有互补特性的多个传感器融合在一起 局部传感器 摄
  • (每日一读2019.10.25)一种基于通用优化方法的多传感器局部里程计估计框架(VINS-Fusion)

    摘要 为了提高机器人的鲁棒性和自主性 越来越多的传感器被安装在机器人上 我们已经看到了不同平台上安装的各种传感器套件 例如地面车辆上的立体摄像机 手机上带有IMU 惯性测量单元 的单目摄像机以及空中机器人上带有IMU的立体摄像机 虽然过去已
  • Gazebo模型下载以及配置--解决Gazebo黑屏原因

    前往ExBot ROS专区下载Gazebo模型 https bitbucket org osrf gazebo models downloads 下载后把文件放在 gazebo下的models文件夹中 span class token fu
  • 相机内外参数以及畸变参数

    关于大佬们的一些见解 下面是引用知乎的一段文字 xff1a 我们从单目视觉说起 平时我们都说要做视觉识别 测量云云 xff0c 然后我们就会去拍照 xff0c 再对数字图像做各种处理 xff0c 颜色处理 灰度化 滤波 边缘检测 霍夫变换
  • cmake学习4--自定义编译选项

    CMake 允许为项目增加编译选项 xff0c 从而可以根据用户的环境和需求选择最合适的编译方案 例如 xff0c 可以将 MathFunctions 库设为一个可选的库 xff0c 如果该选项为 ON xff0c 就使用该库定义的数学函数

随机推荐

  • ROS与C++学习1

    ROS与C 入门教程 构建工作空间 构建Catkin包 搭建开发环境 catkin make 编写简单发布节点和订阅节点 编写简单服务端和客户端 使用类方法作为回调函数 使用Timers类 编写高级的发布器和订阅器 Callbacks和Sp
  • IAR的UI界面优化

    显示行数 Tools Options 点击 Editor Tab size xff1a 设置Tab键占用多少个空格Indent size xff1a 应该是设置过行时缩进多少个空格Insert tab xff1a 选了之后在删除Tab时 x
  • MYNTEYE小觅双目摄像头深度版+VINS测试

    小觅双目深度版性能分析 今年 xff08 18年 xff09 11月9号小觅智能科技的深度版双目相机上市 xff0c 于是我在12月初花了2999软妹币购买了120度视角的相机 其中我比较感兴趣的是 双目 43 惯导 43 结构光 的多传感
  • QT+ROS开发

    Qt Creator for ROS 如果想在Qt上进行ros包的开发和GUI界面开发 建议采用下面的方法 http fumacrom com 1mipW Setup Qt Creator for ROS Setup Ubuntu to a
  • PX4、APM无人机仿真连接QGC地面站记录(udp连接、更改home点等)

    文章目录 一 PX41 gazebo 仿真2 连接地面站3 更改 Home点 二 APM 仿真1 执行仿真指令2 连接地面站3 更改 Home 点 本文仅记录仿真指令 xff0c 搭建安装不在此 一 PX4 首先给飞控源码和子目录权限 sp
  • LeetCode 解题笔记(一)总

    文章目录 一 常用技巧二 常用翻译三 题目x 其他9 回文数 2021 12 0911 盛最多水的容器 2022 01 0515 三数之和 2022 01 14 17 电话号码的字母组合 2022 01 1520 有效的括号 2021 12
  • LeetCode 解题笔记(二)数组篇

    文章目录 一 基础篇26 删除排序数组中的重复 2022 01 16122 买卖股票的最佳时机 II 2022 01 17189 轮转数组 2022 01 18217 存在重复元素 2022 01 19136 只出现一次的数字 2021 1
  • LeetCode 解题笔记(四)链表

    文章目录 一 总结二 题目237 删除链表中的节点 xff08 2022 03 10 xff09 19 删除链表的倒数第 N 个结点 xff08 2022 03 11 xff09 206 反转链表 xff08 2022 03 18 xff0
  • QT Quick QML 实例之 Popup 弹出界面

    QT Quick QML 实例之 Popup 弹出界面 一 演示二 实现过程1 居中弹出2 正下方弹出 所有的热爱都要不遗余力 xff0c 真正喜欢它便给它更高的优先级 xff0c 和更多的时间吧 xff01 GIT工程文件在这里 QmlL
  • QGC(GGroundControl) 系统核心架构图

    关于QGC地面站其它文章请点击这里 QGC地面站 UML 核心类图 xff1a xff08 点击图片放大看效果更好 xff09 核心系统分析图 xff1a xff08 点击图片放大看效果更好 xff09 工程结构 xff1a 整个 QGC
  • Qt 国际化翻译,函数外部字符串、Map 翻译(QT_TRANSLATE_NOOP)

    文章目录 1 Qt 的翻译流程2 利用 QT TRANSLATE NOOP 翻译 GitHub 源码 QmlLearningPro xff0c 选择子工程 xff1a TranslationsDemo pro QML 其它文章请点击这里 Q
  • IAR新建工程

    下载库函数 本文介绍基于 IAR 43 官方标准固件库 xff0c 来新建 STM8S003F 工程 xff0c STM8S 的标准固件库可以到 ST 的官方网站中找到并下载 xff1a ST官网 1 在搜索栏上搜索 STM8S003F x
  • RTSP 推流和拉流记录(运行代码)

    文章目录 1 RTSP 推流2 RTSP 拉流 1 RTSP 推流 用C 43 43 11 实现的RTSP服务器和推流器 xff0c 链接如下 RtspServer GitHub原地址 xff1a https github com PHZ7
  • FFmpeg 中 RTSP推流桌面和Android设备延时测试

    文章目录 1 FFMPEG 推流 xff1a 1 1 FFmpeg 源码准备1 2 RTSP 推流服务器 2 执行流程2 1 启动服务器2 2 执行桌面推流2 3 播放 3 安卓测试 1 FFMPEG 推流 xff1a 1 1 FFmpeg
  • Windows 下 GitKraken 6.5.1免费版本安装

    文章目录 1 安装 6 5 1 版本2 更换快捷方式3 登录 用过 GitKraken 都说好 xff0c 不过 xff0c GitKraken 从 6 5 3 版本开始收费 xff0c 它的最后一个免费版本是 6 5 1 xff0c 当你
  • QT 中的多线程之 moveToThread

    文章目录 1 概述2 方法描述3 代码 xff1a 4 运行结果5 注意事项6 结语 1 概述 在 Qt 中 xff0c 多线程也被广泛用于实现后台任务 异步操作 多任务处理等功能 通过使用多线程 xff0c 可以提高程序的响应性和用户体验
  • QT 多线程之继承 QThread

    文章目录 1 概述2 方法描述3 代码 xff1a 4 运行结果5 结语 1 概述 在 Qt 中 xff0c 可以使用 QThread 的两种方式来创建和控制线程 xff1a 继承 QThread 类和使用 QObject moveToTh
  • Qt 多线程同步:互斥锁QMutextLocker 、读写锁 QReadWriteLock、信号量 QSemaphore、 条件变量QWaitConditio、QThread::wait()

    文章目录 1 Qt 多线程为什么需要同步机制 lt font gt 2 多线程有哪些同步机制 2 1 互斥锁 xff08 QMutex xff09 2 2 读写锁 xff08 QReadWriteLock xff09 2 3 信号量 xff
  • Windows下 ffmpeg 的 “Protocol not found“ 的解决

    文章目录 1 问题描述2 排查方法记录2 1 检查代码中编码器是否安装2 2 确定ffmpeg版本号2 3 打印编译参数2 4 查看运行中调用dll 1 问题描述 调用ffmpeg库中 xff0c 如果使用 avformat open in
  • Qt 智能指针介绍: QSharedPointer、QWeakPointer 、QScopedPointer 、QPointer(附实例)

    文章目录 1 概述2 Qt 中有几种智能指针 xff1f 2 1 QSharedPointer 实例2 2 QSharedPointer 与 QWeakPointer 实例2 3 QScopedPointer 实例2 4 QPointer