医院网站建设招标公告,上传网站软件,建设银行网站个人客户,wordpress淘宝主题一、什么是隐式共享
Qt 的隐式共享#xff08;implicit sharing#xff09;机制是一种设计模式#xff0c;用于在进行数据拷贝时提高效率和减少内存占用。
在 Qt 中#xff0c;许多类#xff08;如 QString、QList 等#xff09;都使用了隐式共享机制。这意味着当这些类…一、什么是隐式共享
Qt 的隐式共享implicit sharing机制是一种设计模式用于在进行数据拷贝时提高效率和减少内存占用。
在 Qt 中许多类如 QString、QList 等都使用了隐式共享机制。这意味着当这些类的实例被拷贝时实际上并不会立即进行数据的深拷贝而是共享同一份数据。只有在其中一个实例发生修改时才会进行实际的数据复制以确保数据的独立性,即Copy-On-Write。
隐式共享机制通过引用计数reference counting来实现。每个共享的实例都包含一个引用计数用于记录当前有多少个实例共享同一份数据。当一个实例被拷贝时引用计数会增加当一个实例被销毁时引用计数会减少。只有当引用计数为 1 时才会进行实际的数据复制。
这种设计模式可以提高程序的性能和内存利用率特别是在处理大量数据拷贝的情况下。同时开发者也无需过多关注数据的共享和拷贝从而简化了程序的设计和实现。
总之Qt 的隐式共享机制是一种高效的数据共享和拷贝方式它通过引用计数来实现数据的延迟复制从而提高了程序的性能和内存利用率。
二、隐式共享代码示例
下面是一个简单的例子展示了QString如何使用隐式共享
#include QString
#include QDebugint main() {QString str1 Hello, Qt!;QString str2 str1; // 这里并没有发生真正的数据复制str1和str2共享同一份数据拷贝赋值使用的是浅拷贝的方式qDebug() str1; // 输出 Hello, Qt!qDebug() str2; // 输出 Hello, Qt!str2[0] h; // 在这里由于str2要修改数据所以发生了真正的数据复制str1和str2不再共享数据qDebug() str1; // 输出 Hello, Qt!qDebug() str2; // 输出 hello, Qt!return 0;
}在上述代码中当我们创建str2并将其初始化为str1时并没有发生真正的数据复制str1和str2实际上是共享同一份数据的。只有当我们试图修改str2的数据时才会发生真正的数据复制这就是所谓的写时复制。
这种技术的优点是可以大大减少不必要的数据复制从而提高程序的性能。但是它也有一些缺点例如在多线程环境中可能需要额外的同步操作以防止数据竞争。
在Qt的源码中这种技术的实现主要依赖于引用计数和深拷贝。每个可以共享数据的对象都有一个引用计数当引用计数为1时表示只有一个对象在使用这份数据可以直接修改。当引用计数大于1时表示有多个对象在共享这份数据如果有一个对象要修改数据就需要先进行深拷贝然后再修改新的数据这样就不会影响到其他对象。
三、自定义一个使用隐式共享技术的数据类型
在Qt中你可以通过使用QSharedData和QSharedDataPointer类来实现隐式共享也称为写时复制。
以下是一个简单的例子定义了一个自定义的数据类型MyData它使用了隐式共享技术
#include QSharedData
#include QSharedDataPointerclass MyData : public QSharedData {
public:MyData() : x(0), y(0) {}MyData(int x, int y) : x(x), y(y) {}int x, y;
};class MySharedType {
public:MySharedType() : data(new MyData) {}MySharedType(int x, int y) : data(new MyData(x, y)) {}MySharedType(const MySharedType other) : data(other.data) {}MySharedType operator(const MySharedType other) {if (this ! other)data other.data;return *this;}int x() const { return data-x; }int y() const { return data-y; }void setX(int x) { if (data-x ! x) detach(); data-x x; }void setY(int y) { if (data-y ! y) detach(); data-y y; }private:void detach() { if (data-ref ! 1) data new MyData(*data); }QSharedDataPointerMyData data;
};在这个例子中MyData类是实际存储数据的类它继承自QSharedData。MySharedType类是用户使用的类它包含一个QSharedDataPointer指向MyData实例。当需要修改数据时detach方法会被调用如果有多个MySharedType实例共享同一个MyData实例那么detach方法会创建一个新的MyData实例以实现写时复制。
顺便看看 QSharedData 和QSharedDataPointer 的源码实现
#ifndef QSHAREDDATA_H
#define QSHAREDDATA_H#include QtCore/qglobal.h
#include QtCore/qatomic.h
#if QT_DEPRECATED_SINCE(5, 6)
#include QtCore/qhash.h
#endif
#include QtCore/qhashfunctions.hQT_BEGIN_NAMESPACEtemplate class T class QSharedDataPointer;class
#if QT_VERSION QT_VERSION_CHECK(6, 0, 0)
Q_CORE_EXPORT
#endif
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-countingQSharedData operator(const QSharedData ) delete;~QSharedData() default;
};template class T class QSharedDataPointer
{
public:typedef T Type;typedef T *pointer;/***************************************************//// 分离数据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; }inline bool operator(const QSharedDataPointerT other) const { return d other.d; }inline bool operator!(const QSharedDataPointerT other) const { return d ! other.d; }inline QSharedDataPointer() { d nullptr; }inline ~QSharedDataPointer() { if (d !d-ref.deref()) delete d; }explicit QSharedDataPointer(T *data) noexcept;inline QSharedDataPointer(const QSharedDataPointerT o) : d(o.d) { if (d) d-ref.ref(); }inline QSharedDataPointerT operator(const QSharedDataPointerT 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;}inline QSharedDataPointer operator(T *o) {if (o ! d) {if (o)o-ref.ref();T *old d;d o;if (old !old-ref.deref())delete old;}return *this;}QSharedDataPointer(QSharedDataPointer o) noexcept : d(o.d) { o.d nullptr; }inline QSharedDataPointerT operator(QSharedDataPointerT other) noexcept{QSharedDataPointer moved(std::move(other));swap(moved);return *this;}inline bool operator!() const { return !d; }inline void swap(QSharedDataPointer other) noexcept{ qSwap(d, other.d); }protected:T *clone();private:void detach_helper();T *d;
};template class T inline bool operator(std::nullptr_t p1, const QSharedDataPointerT p2)
{Q_UNUSED(p1);return !p2;
}template class T inline bool operator(const QSharedDataPointerT p1, std::nullptr_t p2)
{Q_UNUSED(p2);return !p1;
}template class T class QExplicitlySharedDataPointer
{
public:typedef T Type;typedef T *pointer;inline T operator*() const { return *d; }inline T *operator-() { return d; }inline T *operator-() const { return d; }inline T *data() const { return d; }inline const T *constData() const { return d; }inline T *take() { T *x d; d nullptr; return x; }inline void detach() { if (d d-ref.loadRelaxed() ! 1) detach_helper(); }inline void reset(){if(d !d-ref.deref())delete d;d nullptr;}inline operator bool () const { return d ! nullptr; }inline bool operator(const QExplicitlySharedDataPointerT other) const { return d other.d; }inline bool operator!(const QExplicitlySharedDataPointerT other) const { return d ! other.d; }inline bool operator(const T *ptr) const { return d ptr; }inline bool operator!(const T *ptr) const { return d ! ptr; }inline QExplicitlySharedDataPointer() { d nullptr; }inline ~QExplicitlySharedDataPointer() { if (d !d-ref.deref()) delete d; }explicit QExplicitlySharedDataPointer(T *data) noexcept;inline QExplicitlySharedDataPointer(const QExplicitlySharedDataPointerT o) : d(o.d) { if (d) d-ref.ref(); }templateclass Xinline QExplicitlySharedDataPointer(const QExplicitlySharedDataPointerX o)
#ifdef QT_ENABLE_QEXPLICITLYSHAREDDATAPOINTER_STATICCAST: d(static_castT *(o.data()))
#else: d(o.data())
#endif{if(d)d-ref.ref();}inline QExplicitlySharedDataPointerT operator(const QExplicitlySharedDataPointerT 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;}inline QExplicitlySharedDataPointer operator(T *o) {if (o ! d) {if (o)o-ref.ref();T *old d;d o;if (old !old-ref.deref())delete old;}return *this;}inline QExplicitlySharedDataPointer(QExplicitlySharedDataPointer o) noexcept : d(o.d) { o.d nullptr; }inline QExplicitlySharedDataPointerT operator(QExplicitlySharedDataPointerT other) noexcept{QExplicitlySharedDataPointer moved(std::move(other));swap(moved);return *this;}inline bool operator!() const { return !d; }inline void swap(QExplicitlySharedDataPointer other) noexcept{ qSwap(d, other.d); }protected:T *clone();private:void detach_helper();T *d;
};template class T
Q_INLINE_TEMPLATE QSharedDataPointerT::QSharedDataPointer(T *adata) noexcept: d(adata)
{ if (d) d-ref.ref(); }template class T
Q_INLINE_TEMPLATE T *QSharedDataPointerT::clone()
{return new T(*d);
}template class T
Q_OUTOFLINE_TEMPLATE void QSharedDataPointerT::detach_helper()
{T *x clone();x-ref.ref();if (!d-ref.deref())delete d;d x;
}template class T
Q_INLINE_TEMPLATE T *QExplicitlySharedDataPointerT::clone()
{return new T(*d);
}template class T
Q_OUTOFLINE_TEMPLATE void QExplicitlySharedDataPointerT::detach_helper()
{T *x clone();x-ref.ref();if (!d-ref.deref())delete d;d x;
}template class T
Q_INLINE_TEMPLATE QExplicitlySharedDataPointerT::QExplicitlySharedDataPointer(T *adata) noexcept: d(adata)
{ if (d) d-ref.ref(); }template class T inline bool operator(std::nullptr_t p1, const QExplicitlySharedDataPointerT p2)
{Q_UNUSED(p1);return !p2;
}template class T inline bool operator(const QExplicitlySharedDataPointerT p1, std::nullptr_t p2)
{Q_UNUSED(p2);return !p1;
}template class T
Q_INLINE_TEMPLATE void swap(QSharedDataPointerT p1, QSharedDataPointerT p2)
{ p1.swap(p2); }template class T
Q_INLINE_TEMPLATE void swap(QExplicitlySharedDataPointerT p1, QExplicitlySharedDataPointerT p2)
{ p1.swap(p2); }template class T
Q_INLINE_TEMPLATE uint qHash(const QSharedDataPointerT ptr, uint seed 0) noexcept
{return qHash(ptr.data(), seed);
}
template class T
Q_INLINE_TEMPLATE uint qHash(const QExplicitlySharedDataPointerT ptr, uint seed 0) noexcept
{return qHash(ptr.data(), seed);
}templatetypename T Q_DECLARE_TYPEINFO_BODY(QSharedDataPointerT, Q_MOVABLE_TYPE);
templatetypename T Q_DECLARE_TYPEINFO_BODY(QExplicitlySharedDataPointerT, Q_MOVABLE_TYPE);QT_END_NAMESPACE#endif // QSHAREDDATA_H