前言
所谓的隐式共享,就是多个对象引用同一数据(参考智能指针),只在修改内容时才创建新的数据副本(即 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()
关注
打赏
最近更新
- 深拷贝和浅拷贝的区别(重点)
- 【Vue】走进Vue框架世界
- 【云服务器】项目部署—搭建网站—vue电商后台管理系统
- 【React介绍】 一文带你深入React
- 【React】React组件实例的三大属性之state,props,refs(你学废了吗)
- 【脚手架VueCLI】从零开始,创建一个VUE项目
- 【React】深入理解React组件生命周期----图文详解(含代码)
- 【React】DOM的Diffing算法是什么?以及DOM中key的作用----经典面试题
- 【React】1_使用React脚手架创建项目步骤--------详解(含项目结构说明)
- 【React】2_如何使用react脚手架写一个简单的页面?