Qt开发:智能指针的介绍和使用

一、QScopedPointer

1.1 概念
  QScopedPointer 是 Qt 提供的独占式智能指针,用于在作用域结束时自动释放对象,避免手动 delete。

主要特点:

  • 独占:每个 QScopedPointer 只能管理一个对象,不能被拷贝。
  • 自动释放:指针超出作用域时,管理的对象会被自动删除。
  • 轻量级:只管理对象生命周期,不维护引用计数。

1.2 常用成员函数

  • data():返回内部原始指针
  • operator->():访问对象成员
  • operator*():解引用对象
  • reset(T* ptr = nullptr):替换管理的对象,释放原对象
  • take():放弃管理权,不删除对象,返回原始指针

1.3 使用示例

#include <QCoreApplication>
#include <QScopedPointer>
#include <QDebug>

class Test {
public:
    Test() { qDebug() << "Test 构造"; }
    ~Test() { qDebug() << "Test 析构"; }
    void hello() { qDebug() << "Hello from Test"; }
};

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

    // 创建一个 QScopedPointer 管理对象
    QScopedPointer<Test> ptr(new Test());

    ptr->hello();        // 访问对象成员
    (*ptr).hello();      // 解引用访问成员

    // 替换管理对象
    ptr.reset(new Test());

    // 获取内部指针但不删除对象
    Test* rawPtr = ptr.take();
    if(rawPtr) {
        rawPtr->hello();
        delete rawPtr;   // 需要手动删除,因为 take() 放弃了管理权
    }

    // ptr 超出作用域时,会自动删除原对象(如果有的话)

    return a.exec();
}

1.4 初始化方法
直接用构造函数初始化(最常用)

QScopedPointer<Test> ptr(new Test());  // 最直接的方式
  • 这种方式最常见,也最安全。
  • 指针在 ptr 超出作用域时自动释放。

默认构造 + reset() 初始化

QScopedPointer<Test> ptr;       // 空指针
ptr.reset(new Test());          // 初始化对象
  • 优点:可以在运行时动态决定管理的对象。
  • 注意:reset() 会先删除原有对象(如果有)。

使用已有裸指针 + take() 接管
如果有一个已经存在的裸指针,也可以用 reset() 或构造函数接管:

Test* raw = new Test();
QScopedPointer<Test> ptr(raw);  // 接管 raw 的管理

注意:不要重复 delete 原始指针,否则会 double free。

如果需要放弃管理权,可以用 take()

Test* raw2 = ptr.take();  // ptr 不再管理 raw2

结合函数返回值初始化

QScopedPointer<Test> createTest() {
    return QScopedPointer<Test>(new Test());
}

auto ptr = createTest();  // 自动管理对象

二、QSharedPointer

2.1 概念
QSharedPointer 是 Qt 提供的 引用计数智能指针,类似于 C++11 的 std::shared_ptr。

  • 多个 QSharedPointer 可以共享同一个对象
  • 当最后一个引用被销毁时,对象会自动释放。
  • 可以与 QWeakPointer 配合使用,避免循环引用。

特点:

  • 自动管理对象生命周期,防止内存泄漏。
  • 内部维护 引用计数。
  • 可以安全地在多个地方共享同一对象。

2.2 常用成员函数

  • data():返回内部原始指针
  • operator->():访问对象成员
  • operator*():解引用对象
  • isNull():判断是否为空
  • clear():释放当前管理的对象
  • swap():交换两个 QSharedPointer 管理的对象
  • useCount():返回当前引用计数

2.3 基本使用示例

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

class Test {
public:
    Test() { qDebug() << "Test 构造"; }
    ~Test() { qDebug() << "Test 析构"; }
    void hello() { qDebug() << "Hello from Test"; }
};

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

    // 创建 QSharedPointer 管理对象
    QSharedPointer<Test> ptr1(new Test());
    qDebug() << "ptr1.useCount() =" << ptr1.useCount();

    // 拷贝 QSharedPointer
    QSharedPointer<Test> ptr2 = ptr1;
    qDebug() << "ptr1.useCount() =" << ptr1.useCount();
    qDebug() << "ptr2.useCount() =" << ptr2.useCount();

    // 访问对象
    ptr1->hello();
    (*ptr2).hello();

    // 清空一个指针
    ptr1.clear();
    qDebug() << "ptr1 cleared";
    qDebug() << "ptr2.useCount() =" << ptr2.useCount();

    // 当最后一个指针超出作用域,Test 对象自动析构
    return a.exec();
}

为了避免循环引用,可以使用 QWeakPointer:

QSharedPointer<Test> shared(new Test());
QWeakPointer<Test> weak = shared;

if (auto ptr = weak.toStrongRef()) {
    ptr->hello(); // 转换成 QSharedPointer 再使用
}

三、QWeakPointer

3.1 概念
QWeakPointer 是 Qt 提供的 弱引用智能指针,用于与 QSharedPointer 搭配使用。

  • 作用:观察 QSharedPointer 管理的对象,但 不增加引用计数。
  • 目的:防止循环引用(循环引用会导致对象无法释放)。

特点:

  • 不会阻止对象析构。
  • 可以通过 toStrongRef() 临时获取 QSharedPointer 使用对象。
  • 如果对象已经析构,toStrongRef() 会返回空指针。

3.2 常用成员函数:

  • toStrongRef():转换成 QSharedPointer,如果对象还存在则返回有效 QSharedPointer,否则为空
  • isNull():判断对象是否已经析构或不存在
  • clear():释放对对象的弱引用

3.2 基本使用示例

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

class Test {
public:
    Test() { qDebug() << "Test 构造"; }
    ~Test() { qDebug() << "Test 析构"; }
    void hello() { qDebug() << "Hello from Test"; }
};

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

    // 创建 QSharedPointer 管理对象
    QSharedPointer<Test> shared(new Test());

    // 创建 QWeakPointer 观察 shared
    QWeakPointer<Test> weak = shared;

    qDebug() << "shared.useCount() =" << shared.useCount();
    qDebug() << "weak.isNull() =" << weak.isNull();

    // 临时获取 QSharedPointer 使用对象
    if (auto temp = weak.toStrongRef()) {
        temp->hello();
        qDebug() << "temp.useCount() =" << temp.useCount();
    }

    // 清空原始 QSharedPointer
    shared.clear();
    qDebug() << "shared cleared";

    // 再次尝试获取对象
    if (auto temp = weak.toStrongRef()) {
        temp->hello();
    } else {
        qDebug() << "对象已被销毁,无法访问";
    }

    return a.exec();
}

使用场景:
1. 打破循环引用

  • 当对象 A 和对象 B 都持有 QSharedPointer 对方时,会形成循环引用。
  • 将其中一个 QSharedPointer 改为 QWeakPointer,即可让对象正常析构。

2. 观察对象生命周期

  • QWeakPointer 可以安全地检查对象是否存在,而不会阻止它被析构。

3. 临时访问共享对象

  • 通过 toStrongRef() 获取临时 QSharedPointer 安全使用对象。
Qt 开发中,智能指针使用非常普遍,并且 Qt 提供了一套自己的智能指针机制,其功能与 C++11 标准中的智能指针类似,甚至在某些方面更为强大。因此,当开发者基于 Qt 进行开发时,通常会优先选择使用 Qt 自带的智能指针,而不是 C++11 的标准智能指针Qt 中常用的智能指针包括 `QPointer`、`QSharedPointer` `QScopedPointer`(或 `std::unique_ptr` 在现代 C++ 中的等价物)。它们分别适用于不同的场景: - **`QPointer`** 是一种弱引用指针,用于跟踪一个 QObject 派生类对象。当所指向的对象被删除时,`QPointer` 会自动置为 `nullptr`,从而避免了悬空指针的问题 [^2]。 - **`QSharedPointer<T>`** 是 Qt 中的共享指针实现,多个 `QSharedPointer` 实例可以共享同一个对象的所有权,并在最后一个指针销毁时自动释放资源 [^3]。 - **`QScopedPointer`** 类似于 C++11 的 `std::unique_ptr`,表示独占所有权的智能指针,适用于不需要共享资源管理的场景。 例如,定义使用 `QSharedPointer` 的方式如下: ```cpp QSharedPointer<Test> spt(new Test("Delphi Tang")); // 创建一个共享指针 QSharedPointer<Test> spt1 = spt; // 共享所有权 spt->print(); // 调用对象方法 ``` 由于 Qt 智能指针Qt 对象模型深度集成,尤其在处理 QObject 及其派生类时表现出良好的兼容性易用性,这使得它们在实际项目中得到了广泛的应用 [^1]。 ### 常见优势 - Qt智能指针能够很好地与信号槽机制以及 QObject 层次结构配合使用。 - 它们提供了额外的功能,如自动清理、跨线程支持等。 - 针对特定需求,如内存管理资源追踪,Qt 智能指针提供了比标准库更丰富的接口设计。 总之,在 Qt 项目中合理地使用智能指针可以显著提升代码的安全性可维护性,减少手动内存管理带来的风险。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值