Qt:智能指针QScopedPointer 的使用(以及如何写一个QScopedPointer )

前言

本文讲述QScopedPointer 的使用,以及自己如何写一个QScopedPointer .

正文

QScopedPointer 的常用方法

以下是 QScopedPointer 的一些常用方法及其详细说明:

  1. 构造函数

    • QScopedPointer<T> ptr(new T);
    • 用于创建一个 QScopedPointer,并管理一个新分配的对象。
  2. reset()

    • void reset(T *ptr = nullptr);
    • 释放当前管理的对象并重新指向新的对象。如果传入 nullptr,则仅释放当前管理的对象。
  3. operator->()

    • T *operator->() const;
    • 用于访问指针指向的对象的成员函数或变量。
  4. operator*()

    • T &operator*() const;
    • 用于访问指针指向的对象。
  5. T *data()

    • 返回指针指向的对象的裸指针。
  6. T *get() const noexcept

    • 功能:与 data() 功能相同,也返回当前 QScopedPointer 管理的对象的裸指针。
    • noexcept:表示该函数不会抛出异常。
    • 用法:通常与 data() 等效,可以使用 get() 方法来访问裸指针。
  7. bool isNull() const noexcept

    • 功能:检查 QScopedPointer 是否为空(即它是否指向一个有效的对象)。
    • noexcept:表示该函数不会抛出异常。
    • 用法:用于检查智能指针是否为空,常用于条件判断。
  8. T *take() noexcept

    • 功能:释放 QScopedPointer 管理的对象并返回裸指针,智能指针不再管理该对象。
    • noexcept:表示该函数不会抛出异常。
    • 用法:当你需要将对象的所有权转移到外部使用时,可以使用 take() 方法。调用 take() 后,智能指针不再管理该对象,因此外部代码需要负责删除它。
  9. void swap(QScopedPointer<T, Cleanup> &other) noexcept

    • 功能:交换当前 QScopedPointer 和另一个 QScopedPointer 的管理对象。
    • noexcept:表示该函数不会抛出异常。
    • 用法:用于交换两个 QScopedPointer 的对象,常用于实现自定义类型的 swap 操作或在算法中交换两个智能指针。

使用示例

// TestSmartPointer.h
#ifndef TESTSMARTPOINTER_H
#define TESTSMARTPOINTER_H

#include <QObject>
#include <QScopedPointer>
#include <QSharedPointer>
class TestSmartPointer:public QObject
{
    Q_OBJECT
public:
    TestSmartPointer();
    ~TestSmartPointer();
    void doSomething();
};

#endif // TESTSMARTPOINTER_H

// TestSmartPointer.cpp
#include "testsmartpointer.h"
#include <QDebug>
TestSmartPointer::TestSmartPointer()
{
    qDebug()<<"对象创建";
}

TestSmartPointer::~TestSmartPointer()
{
    qDebug()<<"对象销毁";
}

void TestSmartPointer::doSomething()
{
    qDebug()<<"其它处理逻辑";
}


// main.cpp
#include <QCoreApplication>
#include "testsmartpointer.h"
#include "QDebug"

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    QScopedPointer<TestSmartPointer> smartPointer(new TestSmartPointer());
    smartPointer->doSomething();
    TestSmartPointer* tPointer = smartPointer.data();
    tPointer->doSomething();
    // 仅仅释放当前对象
    smartPointer.reset(nullptr);
    if (smartPointer.isNull()) {
        qDebug()<<"smartPointer is null";
    } else {
        qDebug()<<"smartPointer is not null";
    }


    QScopedPointer<TestSmartPointer> smartPointer2(new TestSmartPointer());
    if (smartPointer2.isNull()) {
        qDebug()<<"smartPointer2 is null";
    } else {
        qDebug()<<"smartPointer2 is not null";
    }
    // 智能指针不再管理该对象,需要自己管理
    TestSmartPointer* tPointer2 = smartPointer2.take();
    tPointer2->doSomething();
    delete tPointer2;

    return a.exec();
}

运行结果

在这里插入图片描述

实现类似 QScopedPointer 的智能指针

template <typename T>
class ScopedPointerSelf
{
public:
    // 构造函数
    explicit ScopedPointerSelf(T *ptr = nullptr) : m_ptr(ptr) {}

    // 析构函数
    ~ScopedPointerSelf() {
        delete m_ptr;
    }

    // 禁止复制
    ScopedPointerSelf(const ScopedPointerSelf&) = delete;
    ScopedPointerSelf& operator=(const ScopedPointerSelf&) = delete;

    // 允许移动
    ScopedPointerSelf(ScopedPointerSelf&& other) noexcept : m_ptr(other.m_ptr) {
        other.m_ptr = nullptr;
    }

    ScopedPointerSelf& operator=(ScopedPointerSelf&& other) noexcept {
        if (this != &other) {
            delete m_ptr;
            m_ptr = other.m_ptr;
            other.m_ptr = nullptr;
        }
        return *this;
    }

    // 访问对象的方法
    T* operator->() const {
        return m_ptr;
    }

    // 解引用
    T& operator*() const {
        return *m_ptr;
    }
	bool operator!() const {
		return !m_ptr;
	}
	bool isNull() const {
		return !m_ptr;
	}
    // 重置指针
    void reset(T *ptr = nullptr) {
        delete m_ptr;
        m_ptr = ptr;
    }

    // 释放指针
    T* take() {
        T *temp = m_ptr;
        m_ptr = nullptr;
        return temp;
    }

    // 获取裸指针
    T* get() const {
        return m_ptr;
    }

private:
    T *m_ptr;
};

解释

这里只是实现了一个简单的智能指针的功能,肯定和源码中的没法比,不过该有的功能也都有。

  1. 构造函数和析构函数:构造函数初始化指针,析构函数自动删除管理的对象。
  2. 禁用复制:禁用复制构造函数和赋值操作符,以防止不必要的对象复制。
  3. 移动构造函数和移动赋值操作符:允许移动构造和移动赋值,以便在移动时转移资源所有权。
  4. 重置和释放:提供 reset()take() 方法来管理指针的生命周期和获取裸指针。

使用

// 将我上述的内容放到testSmartPointer.h中,然后在main.cpp中
// 简单更改一下就能用了
#include <QCoreApplication>
#include "testsmartpointer.h"
#include "QDebug"

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    ScopedPointerSelf<TestSmartPointer> smartPointer(new TestSmartPointer());
    smartPointer->doSomething();
    TestSmartPointer* tPointer = smartPointer.get();
    tPointer->doSomething();
    // 仅仅释放当前对象
    smartPointer.reset(nullptr);
    if (smartPointer.isNull()) {
        qDebug()<<"smartPointer is null";
    } else {
        qDebug()<<"smartPointer is not null";
    }


    ScopedPointerSelf<TestSmartPointer> smartPointer2(new TestSmartPointer());
    if (smartPointer2.isNull()) {
        qDebug()<<"smartPointer2 is null";
    } else {
        qDebug()<<"smartPointer2 is not null";
    }
    // 智能指针不再管理该对象,需要自己管理
    TestSmartPointer* tPointer2 = smartPointer2.take();
    tPointer2->doSomething();
    delete tPointer2;

    return a.exec();
}

运行结果

在这里插入图片描述

小结

请指教

### 如何在 Qt使用智能指针 #### 一、Qt 智能指针简介 Qt 提供了几种智能指针类来帮助开发者更好地管理动态分配的对象,从而减少内存泄漏的风险并提高代码的安全性和可读性[^1]。这些智能指针包括但不限于 `std::unique_ptr`, `std::shared_ptr`, `QScopedPointer`, `QPointer`, 和 `QSharedPointer`。 --- #### 二、常见智能指针及其使用方法 ##### 1. **`std::unique_ptr`** `std::unique_ptr` 是 C++ 标准库中的独占所有权智能指针,它确保同一时间只有一个指针拥有该对象的所有权。当 `std::unique_ptr` 被销毁时,其所拥有的对象也会被自动释放。 ```cpp #include <memory> #include <iostream> int main() { std::unique_ptr<int> uniquePtr = std::make_unique<int>(42); std::cout << *uniquePtr << std::endl; // uniquePtr 自动析构,无需手动删除 } ``` 此示例展示了如何创建和使用 `std::unique_ptr` 来管理堆上分配的整数对象。 --- ##### 2. **`std::shared_ptr`** `std::shared_ptr` 支持多个指针共同拥有同一个对象。它的引用计数机制会在最后一个 `std::shared_ptr` 销毁时自动释放所管理的对象。 ```cpp #include <memory> #include <iostream> void useShared(std::shared_ptr<int> sharedPtr) { std::cout << "Use count: " << sharedPtr.use_count() << ", Value: " << *sharedPtr << std::endl; } int main() { auto sharedPtr = std::make_shared<int>(10); useShared(sharedPtr); // 当所有 shared_ptr 都超出作用域时,对象会被释放 } ``` 上述代码演示了 `std::shared_ptr` 的基本用法以及引用计数的工作原理。 --- ##### 3. **`QScopedPointer`** `QScopedPointer` 是 Qt 特定的一种智能指针,类似于 `std::unique_ptr`,但它仅限于单线程环境下的简单资源管理。 ```cpp #include <QScopedPointer> #include <QDebug> class MyClass { public: void sayHello() const { qDebug() << "Hello from MyClass"; } }; int main() { QScopedPointer<MyClass> scopedPtr(new MyClass()); scopedPtr->sayHello(); // scopedPtr 自动析构,无需手动 delete } ``` 这段代码说明了如何利用 `QScopedPointer` 管理自定义类型的实例。 --- ##### 4. **`QPointer`** `QPointer` 是一种特殊的弱指针,专门用于跟踪继承自 `QObject` 的对象。它可以检测目标对象是否已被销毁,并提供保护以防止悬挂指针问题。 ```cpp #include <QPointer> #include <QObject> #include <QDebug> class MyObject : public QObject { Q_OBJECT public slots: void doSomething() const { qDebug() << "Doing something..."; } }; int main() { QPointer<MyObject> ptr = new MyObject(); if (ptr) { ptr->doSomething(); } delete ptr.data(); // 手动删除对象 if (!ptr) { qDebug() << "Pointer is null after deletion"; } } ``` 这里展示的是 `QPointer` 的典型用途——监控 `QObject` 子类的生命期[^2]。 --- ##### 5. **`QSharedPointer`** `QSharedPointer` 是 Qt 实现的一个共享所有权智能指针,功能与 `std::shared_ptr` 类似,但在某些情况下更适合与 Qt 数据结构一起使用。 ```cpp #include <QSharedPointer> #include <QString> #include <QDebug> struct Person { QString name; int age; }; int main() { QSharedPointer<Person> person(new Person{ "Alice", 30 }); qDebug() << person->name << person->age; // 复制指针不会复制实际数据 QSharedPointer<Person> anotherPerson = person; qDebug() << anotherPerson->name << anotherPerson->age; // 当两个指针都超出范围时,底层对象才会被释放 } ``` 以上例子解释了 `QSharedPointer` 的行为模式及其与其他指针的区别。 --- #### 三、注意事项 - 不同类型的智能指针适用于不同的场景;选择不当可能导致性能下降或者逻辑错误[^3]。 - 如果需要从弱指针获取强指针,则务必先验证对象的有效性再操作[^4]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值