文章目录
- 概述
- 隐式共享细节
- 类列表
Qt中的许多c++类使用隐式数据共享来最大化资源使用并最小化复制。隐式共享类作为参数传递时既安全又高效,因为只传递指向数据的指针,并且只有当函数写入数据时才会复制数据,即写时复制(copy-on-write)。
概述
共享类由指向包含引用计数的共享数据块的指针和数据组成
当创建共享对象时,它将引用计数设置为1。每当新对象引用共享数据时,引用计数递增,当对象取消引用共享数据时,引用计数递减。当引用计数变为零时,将删除共享数据。
在处理共享对象时,有两种复制对象的方法。我们通常讲深(deep)拷贝和浅(shallow)拷贝。深度拷贝意味着复制一个对象。浅拷贝是一种引用拷贝,即只是一个指向共享数据块的指针。就内存和CPU而言,进行深度复制可能代价高昂。创建浅拷贝非常快,因为它只需要设置一个指针并增加引用计数
隐式共享对象的对象赋值(operator=())是使用浅拷贝实现的。
共享的好处是程序不需要不必要地复制数据,从而减少内存使用和数据复制。对象可以很容易地分配,作为函数参数发送,并从函数返回
隐性分享大多发生在幕后;程序员很少需要担心这个问题。然而,Qt的容器迭代器与STL中的容器迭代器具有不同的行为Qt学习笔记1.3.1 Qt Core-容器类
在多线程应用程序中,隐式共享发生Qt学习笔记1.2.5 Qt Core线程与并发编程之Qt模块中的线程支持
在实现自己的隐式共享类时,请使用QSharedData和QSharedDataPointer类
隐式共享细节
如果对象即将更改且引用计数大于1,隐式共享会自动将对象从共享块中分离出来。(这通常被称为写时复制或值语义。)
隐式共享类控制其内部数据。在任何修改其数据的成员函数中,它在修改数据之前自动分离。但是,请注意容器迭代器的特殊情况Qt学习笔记1.3.1 Qt Core-容器类
QPen类使用隐式共享,从所有更改内部数据的成员函数中分离共享数据。
void QPen::setStyle(Qt::PenStyle style)
{
detach(); // 与公共数据分离
d->style = style; // 设置style成员
}
void QPen::detach()
{
if (d->ref != 1) {
... // 执行深拷贝
}
}
类列表
如果要更改对象,下面列出的类将自动与公共数据分离。程序员甚至不会注意到对象是共享的。因此,您应该将它们的单独实例视为单独的对象。它们将始终作为单独的对象,但在任何可能的情况下都具有共享数据的额外好处。出于这个原因,您可以将这些类的实例作为参数按值传递给函数,而不必担心复制开销。
例:
QPixmap p1, p2;
p1.load("image.bmp");
p2 = p1; // p1和p2共享数据
QPainter paint;
paint.begin(&p2); // p2从p1中分离
paint.drawText(0,50, "Hi");
paint.end();
在这个例子中,p1和p2共享数据,直到对p2调用QPainter::begin(),因为绘制像素图会修改它。
其他隐式共享数据类见原文https://doc.qt.io/archives/qt-5.12/implicit-sharing.html