Qt学习-隐式共享(Implicit Sharing)

 原文地址 Implicit Sharing | Qt Core 6.5.0

Qt 中的许多 C++ 类使用隐式数据共享来最大化资源使用并最小化复制。 当作为参数传递时,隐式共享类既安全又高效,因为只传递指向数据的指针,并且只有当函数写入数据时才会复制数据,即写时复制。

概述

共享类由指向包含引用计数和数据的共享数据块的指针组成。

创建共享对象时,它会将引用计数设置为 1。每当新对象引用共享数据时,引用计数就会增加,而当对象取消引用共享数据时,引用计数就会减少。 当引用计数变为零时,共享数据将被删除。

在处理共享对象时,有两种复制对象的方法。 我们通常说深拷贝和浅拷贝。 深拷贝意味着复制一个对象。 浅拷贝是引用拷贝,即只是指向共享数据块的指针。 就内存和 CPU 而言,进行深拷贝可能会很昂贵。 制作浅拷贝非常快,因为它只涉及设置指针和增加引用计数。

隐式共享对象的对象分配(使用 operator=())是使用浅拷贝实现的。

共享的好处是程序不需要不必要地复制数据,从而减少内存使用和数据复制。对象可以很容易地被赋值,作为函数参数发送,并从函数返回。

隐式共享主要发生在幕后;程序员很少需要担心它。然而,Qt 的容器迭代器与 STL 中的容器迭代器有不同的行为。阅读隐式共享迭代器问题(后面会讲)。

在多线程应用程序中,会发生隐式共享,但是要注意线程安全问题

在实现您自己的隐式共享类时,请使用 QSharedData 和 QSharedDataPointer 类。

详细介绍

如果对象即将更改并且引用计数大于 1,则隐式共享会自动将对象从共享块中分离出来。 (这通常称为写时复制或值语义。)

隐式共享类可以控制其内部数据。 在修改其数据的任何成员函数中,它会在修改数据之前自动分离。 但是,请注意容器迭代器的特殊情况; 请参阅隐式共享迭代器问题。

使用隐式共享的 QPen 类从所有更改内部数据的成员函数中的共享数据分离。

代码片段:

void QPen::setStyle(Qt::PenStyle style)
{
    detach();           // detach from common data
    d->style = style;   // set the style member
}
​
void QPen::detach()
{
    if (d->ref != 1) {
        ...             // perform a deep copy
    }
}

如果对象将要更改,下面列出的类(见原文)会自动从公共数据中分离出来。 程序员甚至不会注意到对象是共享的。 因此,您应该将它们的单独实例视为单独的对象。 它们将始终表现为独立的对象,但具有尽可能共享数据的额外好处。 因此,您可以按值将这些类的实例作为参数传递给函数,而无需担心复制开销。

举例:

QPixmap p1, p2;
p1.load("image.bmp");
p2 = p1;                        // p1 and p2 share data
​
QPainter paint;
paint.begin(&p2);               // cuts p2 loose from p1
paint.drawText(0,50, "Hi");
paint.end();

在此示例中,p1 和 p2 共享数据直到为 p2 调用 QPainter::begin(),因为绘制像素图将修改它。

隐式共享迭代器问题

隐式共享对 STL 样式的迭代器有另一个影响:当迭代器在容器上处于活动状态时,您应该避免复制容器。 迭代器指向一个内部结构,如果你复制一个容器,你应该非常小心你的迭代器。 例如:

QList<int> a, b;
a.resize(100000); // make a big list filled with 0.
​
QList<int>::iterator i = a.begin();
// WRONG way of using the iterator i:
b = a; // 此时b和a共享数据
​
a[0] = 5; 
// 修改了a的数据,a拷贝了一份,从共享数据分离
// 但是i仍然指向共享数据,即此时只指向b
​
b.clear(); // 此时 i 无效
​
int j = *i; // 读取无效数据,可能会导致crash
/*
    The data from b (which i pointed to) is gone.
    This would be well-defined with STL containers (and (*i) == 5),
    but with QList this is likely to crash.
*/

上面的示例仅显示了 QList 的问题,但所有隐式共享的 Qt 容器都存在该问题。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值