【Qt】: QPointer详解

news2025/1/24 6:58:20

考古: 《Qt智能指针之QScopedPointer》

QPointer是Qt框架中的一个智能指针类,用于安全地管理QObject派生对象的指针。它的主要功能是自动将指针置为nullptr,当它所指向的QObject对象被销毁时。这在Qt应用程序中非常有用,因为QObject对象通常会在其父对象被销毁时自动销毁。

一、QPointer的特性和用法

  1. 自动置空

    • QPointer会在其指向的QObject对象被销毁时自动将自身置为nullptr。这可以防止悬空指针(dangling pointer)问题。
  2. 使用场景

    • 适用于需要在多个地方引用同一个QObject对象的场景,尤其是当对象的生命周期不由你直接控制时。
    • 常用于Qt信号和槽机制中,确保槽函数中使用的对象在信号发出时仍然有效。
  3. QSharedPointerQScopedPointer的区别

    • QPointer不负责对象的内存管理,它只是一个观察者。
    • QSharedPointerQScopedPointer负责对象的生命周期管理,前者通过引用计数,后者通过作用域。

二、示例代码

以下是一个简单的示例,展示如何使用QPointer

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

class MyObject : public QObject {
    Q_OBJECT
public:
    MyObject() { qDebug() << "MyObject created"; }
    ~MyObject() { qDebug() << "MyObject destroyed"; }
};

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

    MyObject* obj = new MyObject();
    QPointer<MyObject> ptr(obj);

    qDebug() << "Pointer is valid:" << !ptr.isNull();

    delete obj;  // Manually delete the object

    qDebug() << "Pointer is valid after deletion:" << !ptr.isNull();

    return a.exec();
}
    1. 创建对象
      MyObject* obj = new MyObject();:动态分配一个MyObject实例。
    1. 使用QPointer
      -QPointer<MyObject> ptr(obj);:创建一个QPointer,指向obj
    1. 检查指针有效性
      ptr.isNull():检查QPointer是否为空。
    1. 删除对象
      delete obj;:手动删除obj,此时ptr会自动变为nullptr
    1. 输出结果
      在对象被删除后,ptr.isNull()返回true,表明指针已被置空。

关键点

  • 安全性QPointer提供了一种安全的方式来引用QObject对象,避免悬空指针。
  • 非所有权QPointer不负责对象的内存管理,只是一个观察者。
  • 适用性:适用于需要在多个地方引用同一个QObject对象的场景,尤其是在信号和槽机制中。

三、QPointer 源码赏析

/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtCore module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or (at your option) the GNU General
** Public license version 3 or any later version approved by the KDE Free
** Qt Foundation. The licenses are as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/

#ifndef QPOINTER_H
#define QPOINTER_H

#include <QtCore/qsharedpointer.h>
#include <QtCore/qtypeinfo.h>

#ifndef QT_NO_QOBJECT

QT_BEGIN_NAMESPACE

class QVariant;

template <class T>
class QPointer
{
    Q_STATIC_ASSERT_X(!std::is_pointer<T>::value, "QPointer's template type must not be a pointer type");

    template<typename U>
    struct TypeSelector
    {
        typedef QObject Type;
    };
    template<typename U>
    struct TypeSelector<const U>
    {
        typedef const QObject Type;
    };
    typedef typename TypeSelector<T>::Type QObjectType;
    QWeakPointer<QObjectType> wp;
public:
    inline QPointer() { }
    inline QPointer(T *p) : wp(p, true) { }
    // compiler-generated copy/move ctor/assignment operators are fine!
    // compiler-generated dtor is fine!

#ifdef Q_QDOC
    // Stop qdoc from complaining about missing function
    ~QPointer();
#endif

    inline void swap(QPointer &other) { wp.swap(other.wp); }

    inline QPointer<T> &operator=(T* p)
    { wp.assign(static_cast<QObjectType*>(p)); return *this; }

    inline T* data() const
    { return static_cast<T*>( wp.data()); }
    inline T* operator->() const
    { return data(); }
    inline T& operator*() const
    { return *data(); }
    inline operator T*() const
    { return data(); }

    inline bool isNull() const
    { return wp.isNull(); }

    inline void clear()
    { wp.clear(); }
};
template <class T> Q_DECLARE_TYPEINFO_BODY(QPointer<T>, Q_MOVABLE_TYPE);

template <class T>
inline bool operator==(const T *o, const QPointer<T> &p)
{ return o == p.operator->(); }

template<class T>
inline bool operator==(const QPointer<T> &p, const T *o)
{ return p.operator->() == o; }

template <class T>
inline bool operator==(T *o, const QPointer<T> &p)
{ return o == p.operator->(); }

template<class T>
inline bool operator==(const QPointer<T> &p, T *o)
{ return p.operator->() == o; }

template<class T>
inline bool operator==(const QPointer<T> &p1, const QPointer<T> &p2)
{ return p1.operator->() == p2.operator->(); }

template <class T>
inline bool operator!=(const T *o, const QPointer<T> &p)
{ return o != p.operator->(); }

template<class T>
inline bool operator!= (const QPointer<T> &p, const T *o)
{ return p.operator->() != o; }

template <class T>
inline bool operator!=(T *o, const QPointer<T> &p)
{ return o != p.operator->(); }

template<class T>
inline bool operator!= (const QPointer<T> &p, T *o)
{ return p.operator->() != o; }

template<class T>
inline bool operator!= (const QPointer<T> &p1, const QPointer<T> &p2)
{ return p1.operator->() != p2.operator->() ; }

template<typename T>
QPointer<T>
qPointerFromVariant(const QVariant &variant)
{
    return QPointer<T>(qobject_cast<T*>(QtSharedPointer::weakPointerFromVariant_internal(variant).data()));
}

QT_END_NAMESPACE

#endif // QT_NO_QOBJECT

#endif // QPOINTER_H

QPointer 只有一个成员变量 QWeakPointer<QObjectType> wp; 几乎所有成员函数的操作都是对wp成员变量的操作。其他,比较简单,不过多赘述。

四、QWeakPointer

/****************************************************************************

template <class T>
class QWeakPointer
{
    typedef T *QWeakPointer:: *RestrictedBool;
    typedef QtSharedPointer::ExternalRefCountData Data;

public:
    typedef T element_type;
    typedef T value_type;
    typedef value_type *pointer;
    typedef const value_type *const_pointer;
    typedef value_type &reference;
    typedef const value_type &const_reference;
    typedef qptrdiff difference_type;

    bool isNull() const Q_DECL_NOTHROW { return d == nullptr || d->strongref.load() == 0 || value == nullptr; }
    operator RestrictedBool() const Q_DECL_NOTHROW { return isNull() ? nullptr : &QWeakPointer::value; }
    bool operator !() const Q_DECL_NOTHROW { return isNull(); }
    T *data() const Q_DECL_NOTHROW { return d == nullptr || d->strongref.load() == 0 ? nullptr : value; }

    inline QWeakPointer() Q_DECL_NOTHROW : d(nullptr), value(nullptr) { }
    inline ~QWeakPointer() { if (d && !d->weakref.deref()) delete d; }

#ifndef QT_NO_QOBJECT
    // special constructor that is enabled only if X derives from QObject
#if QT_DEPRECATED_SINCE(5, 0)
    template <class X>
    QT_DEPRECATED inline QWeakPointer(X *ptr) : d(ptr ? Data::getAndRef(ptr) : nullptr), value(ptr)
    { }
#endif
#endif

#if QT_DEPRECATED_SINCE(5, 0)
    template <class X>
    QT_DEPRECATED inline QWeakPointer &operator=(X *ptr)
    { return *this = QWeakPointer(ptr); }
#endif

    QWeakPointer(const QWeakPointer &other) Q_DECL_NOTHROW : d(other.d), value(other.value)
    { if (d) d->weakref.ref(); }
#ifdef Q_COMPILER_RVALUE_REFS
    QWeakPointer(QWeakPointer &&other) Q_DECL_NOTHROW
        : d(other.d), value(other.value)
    {
        other.d = nullptr;
        other.value = nullptr;
    }
    QWeakPointer &operator=(QWeakPointer &&other) Q_DECL_NOTHROW
    { QWeakPointer moved(std::move(other)); swap(moved); return *this; }
#endif
    QWeakPointer &operator=(const QWeakPointer &other) Q_DECL_NOTHROW
    {
        QWeakPointer copy(other);
        swap(copy);
        return *this;
    }

    void swap(QWeakPointer &other) Q_DECL_NOTHROW
    {
        qSwap(this->d, other.d);
        qSwap(this->value, other.value);
    }

    inline QWeakPointer(const QSharedPointer<T> &o) : d(o.d), value(o.data())
    { if (d) d->weakref.ref();}
    inline QWeakPointer &operator=(const QSharedPointer<T> &o)
    {
        internalSet(o.d, o.value);
        return *this;
    }

    template <class X>
    inline QWeakPointer(const QWeakPointer<X> &o) : d(nullptr), value(nullptr)
    { *this = o; }

    template <class X>
    inline QWeakPointer &operator=(const QWeakPointer<X> &o)
    {
        // conversion between X and T could require access to the virtual table
        // so force the operation to go through QSharedPointer
        *this = o.toStrongRef();
        return *this;
    }

    template <class X>
    bool operator==(const QWeakPointer<X> &o) const Q_DECL_NOTHROW
    { return d == o.d && value == static_cast<const T *>(o.value); }

    template <class X>
    bool operator!=(const QWeakPointer<X> &o) const Q_DECL_NOTHROW
    { return !(*this == o); }

    template <class X>
    inline QWeakPointer(const QSharedPointer<X> &o) : d(nullptr), value(nullptr)
    { *this = o; }

    template <class X>
    inline QWeakPointer &operator=(const QSharedPointer<X> &o)
    {
        QSHAREDPOINTER_VERIFY_AUTO_CAST(T, X); // if you get an error in this line, the cast is invalid
        internalSet(o.d, o.data());
        return *this;
    }

    template <class X>
    bool operator==(const QSharedPointer<X> &o) const Q_DECL_NOTHROW
    { return d == o.d; }

    template <class X>
    bool operator!=(const QSharedPointer<X> &o) const Q_DECL_NOTHROW
    { return !(*this == o); }

    inline void clear() { *this = QWeakPointer(); }

    inline QSharedPointer<T> toStrongRef() const { return QSharedPointer<T>(*this); }
    // std::weak_ptr compatibility:
    inline QSharedPointer<T> lock() const { return toStrongRef(); }

#if defined(QWEAKPOINTER_ENABLE_ARROW)
    inline T *operator->() const { return data(); }
#endif

private:

#if defined(Q_NO_TEMPLATE_FRIENDS)
public:
#else
    template <class X> friend class QSharedPointer;
    template <class X> friend class QPointer;
#endif

    template <class X>
    inline QWeakPointer &assign(X *ptr)
    { return *this = QWeakPointer<X>(ptr, true); }

#ifndef QT_NO_QOBJECT
    template <class X>
    inline QWeakPointer(X *ptr, bool) : d(ptr ? Data::getAndRef(ptr) : nullptr), value(ptr)
    { }
#endif

    inline void internalSet(Data *o, T *actual)
    {
        if (d == o) return;
        if (o)
            o->weakref.ref();
        if (d && !d->weakref.deref())
            delete d;
        d = o;
        value = actual;
    }

    Data *d;
    T *value;
};

QWeakPointer有两个成员变量,
Data *d; T *value;
它自身在构造函数中只是接收指针变量,并赋值給成员函数,因此他也是也是观察者。其他比较简单,不过多赘述。关于Qt中的引用计数原理和实现,后续另外进行介绍。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2281280.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

SpringBoot篇 单元测试 理论篇

1.单元测试概念介绍 简单来说&#xff0c;单元测试是对软件中的最小可测试单元进行检查和验证。在 Java 中&#xff0c;单元测试的最小单元是类。Spring Boot 提供了 spring-boot-starter-test 依赖&#xff0c;包含了 JUnit、Mockito、Hamcrest 等常用的测试框架1。&#xff0…

Formality:不可读(unread)的概念

相关阅读 Formalityhttps://blog.csdn.net/weixin_45791458/category_12841971.html?spm1001.2014.3001.5482https://blog.csdn.net/weixin_45791458/category_12841971.html?spm1001.2014.3001.5482 在Formality中有时会遇到不可读(unread)这个概念&#xff0c;本文就将对此…

ThreeJS示例教程200+【目录】

Three.js 是一个强大的 JavaScript 库,旨在简化在网页上创建和展示3D图形的过程。它基于 WebGL 技术,但提供了比直接使用 WebGL 更易于使用的API,使得开发者无需深入了解 WebGL 的复杂细节就能创建出高质量的3D内容。 由于目前内容还不多,下面的内容暂时做一个占位。 文章目…

【前端】Hexo 部署指南_hexo-deploy-git·GitHub Actions·Git Hooks

文章目录 前言基于 hexo-deploy-git基于 GitHub Actions基于 Git Hooks云平台端服务器端Git HooksSSHNginx 本地机端原理参考 前言 原文地址&#xff1a;https://blog.dwj601.cn/FrontEnd/Hexo/hexo-deployment/ #mermaid-svg-dfuCXqzZCx5I07IO {font-family:"trebuchet …

法律与认知战争:新时代的战略博弈

文章目录 前言全文摘要与关键词一、影响意志二、通过网络空间进行认知战1、网络行动的影响>行为本身2、与破坏性网络攻击相反,数字影响力行动可以产生战略效果三、法律作为一种战争工具四、如何反制法律战的使用?1、自由民主国家需要认识到俄罗斯等国的认知战在意图和深度上…

【Linux】其他备选高级IO模型

其他高级 I/O 模型 以上基本介绍的都是同步IO相关知识点&#xff0c;即在同步I/O模型中&#xff0c;程序发起I/O操作后会等待I/O操作完成&#xff0c;即程序会被阻塞&#xff0c;直到I/O完成。整个I/O过程在同一个线程中进行&#xff0c;程序在等待期间不能执行其他任务。下面…

Arduino D1 通过 Wi-Fi 控制 LED

Arduino D1 通过 Wi-Fi 控制 LED 硬件连接 将 LED 的正极&#xff08;长脚&#xff09;连接到 Arduino D1 的 D1 引脚。将 LED 的负极&#xff08;短脚&#xff09;通过一个电阻&#xff08;例如 220 欧姆&#xff09;连接到 Arduino D1 的 GND 引脚。 安装必要的库 在 Ard…

Flutter:自定义Tab切换,订单列表页tab,tab吸顶

1、自定义tab切换 view <Widget>[// 好评<Widget>[TDImage(assetUrl: assets/img/order4.png,width: 36.w,height: 36.w,),SizedBox(width: 10.w,),TextWidget.body(好评,size: 24.sp,color: controller.tabIndex 0 ? AppTheme.colorfff : AppTheme.color999,),]…

Tailscale 配置 subnet 实现访问 Openwrt 路由器下的子网

Openwrt 安装 Tailscale 参考 OpenWrt 配置 Tailscale 内网穿透。 tailscale两台openwrt(双lan)网对网(site to site)互通OpenWrt安装配置Tailscale 在 OpenWrt 上使用 Tailscale 使用 tailscale subnet 在openwrt terminal 执行 tailscale up --advertise-routes192.168.…

低代码可视化-转盘小游戏可视化-代码生成器

转盘小程序是一种互动工具&#xff0c;它通过模拟真实的转盘抽奖或决策体验&#xff0c;为用户提供了一种有趣且公平的选择方式。以下是对转盘小程序的详细介绍&#xff1a; 转盘小程序的应用场景 日常决策&#xff1a;转盘小程序可以帮助用户解决日常生活中的选择困难问题&a…

【Uniapp-Vue3】uni-icons的安装和使用

一、uni-icon的安装 进入到如下页面中&#xff0c;点击“点击下载&安装”。 uni-icons 图标 | uni-app官网 点击“下载插件并导入HBuilder”&#xff0c;如果没有登录就登陆一下 网页中会打开Hbuilder&#xff0c;进入Hbuilder以后&#xff0c;选择需要使用该插件的项目进…

【橘子ES】Kibana的分析能力Analytics简易分析

一、kibana是啥&#xff0c;能干嘛 我们经常会用es来实现一些关于检索&#xff0c;关于分析的业务。但是es本身并没有UI,我们只能通过调用api来完成一些能力。而kibana就是他的一个外置UI&#xff0c;你完全可以这么理解。 当我们进入kibana的主页的时候你可以看到这样的布局。…

一、引论,《组合数学(第4版)》卢开澄 卢华明

零、前言 发现自己数数题做的很烂&#xff0c;重新学一遍组合数学吧。 参考卢开澄 卢华明 编著的《组合数学(第4版)》&#xff0c;只打算学前四章。 通过几个经典问题来了解组合数学所研究的内容。 一、幻方问题 据说大禹治水之前&#xff0c;河里冒出来一只乌龟&#xff0c…

LabVIEW太阳能照明监控系统

在公共照明领域&#xff0c;传统的电力照明系统存在高能耗和维护不便等问题。利用LabVIEW开发太阳能照明监控系统&#xff0c;通过智能控制和实时监测&#xff0c;提高能源利用效率&#xff0c;降低维护成本&#xff0c;实现照明系统的可持续发展。 ​ 项目背景 随着能源危机…

5. 马科维茨资产组合模型+政策意图AI金融智能体(Qwen-Max)增强方案(理论+Python实战)

目录 0. 承前1. AI金融智能体1.1 What is AI金融智能体1.2 Why is AI金融智能体1.3 How to AI金融智能体 2. 数据要素&计算流程2.1 参数集设置2.2 数据获取&预处理2.3 收益率计算2.4 因子构建与预期收益率计算2.5 协方差矩阵计算2.6 投资组合优化2.7 持仓筛选2.8 AI金融…

【华为路由的arp配置】

华为路由的arp配置 ARP&#xff1a;IP地址与MAC地址的映射。 R1: g0/0/0:10.1.1.254/24 g0/0/1:10.1.2.254/24 PC1: 10.1.1.1/16 PC2: 10.1.1.2/16 PC3: 10.1.2.3/16 动态ARP 查看PC1的arp表&#xff0c;可以看到&#xff0c;列表为空。 查看R1的arp表 在PC3上ping命令测…

U3D的.Net学习

Mono&#xff1a;这是 Unity 最初采用的方式&#xff0c;它将 C# 代码编译为中间语言 (IL)&#xff0c;然后在目标平台上使用虚拟机 (VM) 将其转换为本地机器码执行。 IL2CPP&#xff1a;这是一种较新的方法&#xff0c;它会将 C# 代码先编译为 C 代码&#xff0c;再由 C 编译器…

机器学习-线性回归(简单回归、多元回归)

这一篇文章&#xff0c;我们主要来理解一下&#xff0c;什么是线性回归中的简单回归和多元回归&#xff0c;顺便掌握一下特征向量的概念。 一、简单回归 简单回归是线性回归的一种最基本形式&#xff0c;它用于研究**一个自变量&#xff08;输入&#xff09;与一个因变量&…

智能体的核心技能之插件,插件详解和实例 ,扣子免费系列教程(11)

欢迎来到滔滔讲AI&#xff0c;今天我们来学习智能体的核心功能点之一的插件。 插件是通过API连接集成各种平台和服务&#xff0c;它扩展了智能体的能力。平台内置了丰富的插件&#xff0c;我们可以直接调用。 一、什么是插件 首先&#xff0c;插件其实就像一个工具箱。 每个插…

Spring Security(maven项目) 3.0.2.6版本—总

通过实践而发现真理&#xff0c;又通过实践而证实真理和发展真理。从感性认识而能动地发展到理性认识&#xff0c;又从理性认识而能动地指导革命实践&#xff0c;改造主观世界和客观世界。实践、认识、再实践、再认识&#xff0c;这种形式&#xff0c;循环往复以至无穷&#xf…