C 语言

关注公众号 jb51net

关闭
首页 > 软件编程 > C 语言 > Qt QSharedPointer用法

Qt QSharedPointer用法使用小结

作者:华丽的周遭

本文主要介绍了Qt QSharedPointer用法使用小结,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

QSharedPointer 是 Qt 提供的一个共享所有权的智能指针,用于自动管理动态分配对象的生命周期。它通过引用计数(Reference Counting)机制实现:当最后一个指向对象的 QSharedPointer 被销毁或重置时,对象会被自动 delete。这在 C++ 开发中能有效避免内存泄漏,尤其适合需要多模块共享资源的场景(如流媒体中的缓冲区、视频帧对象等)。

一、核心机制:引用计数

二、基本用法

1. 创建 QSharedPointer

QSharedPointer 通常通过以下方式创建:

(1)从原始指针构造(需确保指针唯一由 QSharedPointer 管理)

#include <QSharedPointer>
#include <QDebug>

class MyClass {
public:
    MyClass(int v) : value(v) { qDebug() << "MyClass constructed"; }
    ~MyClass() { qDebug() << "MyClass destroyed"; }
    int value;
};

int main() {
    // 从原始指针构造(注意:原始指针必须是通过 new 分配的)
    QSharedPointer<MyClass> ptr(new MyClass(10)); 
    return 0;
}
// 输出:
// MyClass constructed
// MyClass destroyed(main 结束时 ptr 析构,引用计数归零)

(2)使用 QSharedPointer::create()(Qt 5.10+ 推荐)

更安全的方式(避免原始指针暴露):

auto ptr = QSharedPointer<MyClass>::create(20); // 等价于 new MyClass(20),但更安全

(3)拷贝构造/赋值(共享所有权)

QSharedPointer<MyClass> ptr1(new MyClass(30));
QSharedPointer<MyClass> ptr2 = ptr1; // 拷贝构造,引用计数+1(变为2)
ptr1.reset(); // ptr1 放弃所有权,引用计数-1(变为1)
// 此时 ptr2 仍指向对象,main 结束时 ptr2 析构,对象被释放

2. 访问对象成员

通过 operator->operator*访问对象:

QSharedPointer<MyClass> ptr = QSharedPointer<MyClass>::create(40);
qDebug() << ptr->value; // 输出 40(等价于 (*ptr).value)

3. 重置(放弃所有权)

QSharedPointer<MyClass> ptr(new MyClass(50));
ptr.reset(); // 原对象被删除(输出 "MyClass destroyed"),ptr 变为 nullptr
ptr.reset(new MyClass(60)); // 接管新对象(输出 "MyClass constructed")

4. 判断有效性

QSharedPointer<MyClass> ptr;
if (ptr.isNull()) { 
    qDebug() << "ptr is null";
}

if (ptr) { // 等价于 !ptr.isNull()
    qDebug() << "ptr is not null";
}

5. 获取原始指针

data()get():返回原始指针(谨慎使用,避免外部手动 delete)。

MyClass* rawPtr = ptr.data();
rawPtr->value = 100; // 直接修改对象(不推荐,破坏封装)

三、高级用法

1. 自定义删除器(Deleter)

默认情况下,QSharedPointer 使用 delete释放对象。若对象通过其他方式分配(如 mallocfopen打开的文件),可自定义删除器。

示例:管理 FILE资源*

#include <cstdio>

// 自定义删除器:关闭文件
void fileCloser(FILE* fp) {
    if (fp) fclose(fp);
    qDebug() << "File closed";
}

int main() {
    // 用 lambda 作为删除器(更灵活)
    QSharedPointer<FILE> filePtr(fopen("test.txt", "r"), [](FILE* fp) {
        if (fp) fclose(fp);
        qDebug() << "Custom deleter: File closed";
    });
    
    if (filePtr) {
        char buf[100];
        fgets(buf, sizeof(buf), filePtr.data());
        qDebug() << "Read:" << buf;
    }
    // 离开作用域时,filePtr 析构,调用自定义删除器关闭文件
    return 0;
}

2. 与 QWeakPointer 配合(解决循环引用)

当两个对象互相持有 QSharedPointer 时,会导致循环引用(引用计数无法归零,内存泄漏)。此时需用 QWeakPointer 打破循环(弱引用不增加强引用计数)。

示例:循环引用问题

class B;

class A {
public:
    QSharedPointer<B> bPtr;
    ~A() { qDebug() << "A destroyed"; }
};

class B {
public:
    QSharedPointer<A> aPtr; // 循环引用!A 和 B 互相强引用
    ~B() { qDebug() << "B destroyed"; }
};

int main() {
    QSharedPointer<A> a(new A);
    QSharedPointer<B> b(new B);
    a->bPtr = b; // a 强引用 b(b 的引用计数=2)
    b->aPtr = a; // b 强引用 a(a 的引用计数=2)
    // 离开作用域时,a 和 b 的引用计数各减1(变为1),不会触发析构!
    return 0;
}
// 输出:(无析构信息,内存泄漏)

解决方案:用 QWeakPointer 替代一方的强引用

class B;

class A {
public:
    QSharedPointer<B> bPtr;
    ~A() { qDebug() << "A destroyed"; }
};

class B {
public:
    QWeakPointer<A> aPtr; // 弱引用,不增加 a 的强引用计数
    ~B() { qDebug() << "B destroyed"; }
};

int main() {
    QSharedPointer<A> a(new A);
    QSharedPointer<B> b(new B);
    a->bPtr = b; // b 的引用计数=2(a->bPtr 和 b 本身)
    b->aPtr = a; // a 的引用计数仍为1(仅 a 本身)
    
    // 离开作用域时:
    // a 析构 → a 的引用计数-1(变为0)→ 调用 A 的析构 → a->bPtr 析构 → b 的引用计数-1(变为1)
    // b 析构 → b 的引用计数-1(变为0)→ 调用 B 的析构 → b->aPtr 是弱引用,无影响
    return 0;
}
// 输出:
// A destroyed
// B destroyed

四、注意事项

避免混合管理:不要用多个独立智能指针(如 QSharedPointer 和 std::shared_ptr)管理同一原始指针,会导致重复释放。

线程安全:QSharedPointer 的引用计数操作是线程安全的(原子操作),但对象本身的访问仍需同步(如多线程读写对象成员)。

与 QObject 的配合:QObject 自带父子内存管理机制(deleteLater),若用 QSharedPointer 管理 QObject 派生类,需注意:

不支持数组:QSharedPointer 默认用 delete释放对象,若需管理数组(new T[]),应使用 QSharedPointer<T[]>(Qt 5.6+),它会调用 delete[]

五、总结

QSharedPointer 是 Qt 中管理动态对象的核心工具,通过引用计数自动释放资源,适合多模块共享对象的场景。关键要点:

到此这篇关于Qt QSharedPointer用法使用小结的文章就介绍到这了,更多相关Qt QSharedPointer用法内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文