您当前的位置: 首页 >  ar

龚建波

暂无认证

  • 5浏览

    0关注

    313博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

Qt实现一个隐式共享类(使用QSharedDataPointer)

龚建波 发布时间:2021-12-25 23:55:10 ,浏览量:5

前言

所谓的隐式共享,就是多个对象引用同一数据(参考智能指针),只在修改内容时才创建新的数据副本(即 copy-on-write 写时复制)。大部分 Qt 容器及相关类都是隐式共享的,且提供了 QSharedData 和 QSharedDataPointer 来帮助我们快速地实现自己的隐式共享类(Qt 自带的容器并没有使用该便捷类,是定制化的实现)。

原理

参照 Qt 文档中的示例,要使用 QSharedDataPointer  实现隐式共享,需要定义两个类。一个类继承自 QSharedData 用于存放数据;另一个类定义一个 QSharedDataPointer 模板成员,模板类型就是上一步的 QSharedData 派生类。

class SharedData : public QSharedData { 
};
class SharedObject {
    QSharedDataPointer d;
};

从 Qt 源码我们可以看到, QSharedData 主要是维护了一个引用计数的变量:

class QSharedData
{
public:
    mutable QAtomicInt ref;

    inline QSharedData() noexcept : ref(0) { }
    inline QSharedData(const QSharedData &) noexcept : ref(0) { }

    // using the assignment operator would lead to corruption in the ref-counting
    QSharedData &operator=(const QSharedData &) = delete;
    ~QSharedData() = default;
};

而 QSharedDataPointer 每次拷贝构造和赋值构造都是浅拷贝,只复制 QSharedData 指针的值,并增加引用计数:

    inline QSharedDataPointer(const QSharedDataPointer &o) 
    : d(o.d) { if (d) d->ref.ref(); }

    inline QSharedDataPointer & operator=(const QSharedDataPointer &o) {
        if (o.d != d) {
            if (o.d)
                o.d->ref.ref();
            T *old = d;
            d = o.d;
            if (old && !old->ref.deref())
                delete old;
        }
        return *this;
    }

而写时深拷贝主要是借助接口的 const 声明来判断的,如果是非 const 接口,那么就会进行深拷贝,并修改引用计数:

template  class QSharedDataPointer
{
public:
    //... ...
    inline void detach() { if (d && d->ref.loadRelaxed() != 1) detach_helper(); }
    inline T &operator*() { detach(); return *d; }
    inline const T &operator*() const { return *d; }
    inline T *operator->() { detach(); return d; }
    inline const T *operator->() const { return d; }
    inline operator T *() { detach(); return d; }
    inline operator const T *() const { return d; }
    inline T *data() { detach(); return d; }
    inline const T *data() const { return d; }
    inline const T *constData() const { return d; }

    void QSharedDataPointer::detach_helper()
    {
        T *x = clone();
        x->ref.ref();
        if (!d->ref.deref())
            delete d;
        d = x;
    }

    T *QExplicitlySharedDataPointer::clone()
    {
        return new T(*d);
    }
};

原理上还是很简单的,和智能指针差不多。下面照着示例写一个自己的隐式共享类。

实现
#pragma once
//参照Qt文档:https://doc.qt.io/qt-5/qshareddatapointer.html
#include 
#include 
#include 

//共享的数据
//QSharedData带有原子类型的引用计数
class SharedData : public QSharedData
{
public:
    SharedData() {
        qDebug()            
关注
打赏
1655829268
查看更多评论
0.0396s