Qt 隐式共享

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 P1和p2共享数据【浅拷贝】

QPainter paint;
paint.begin(&p2);               // cuts p2 loose from p1 将p2从p1中分离出来【深拷贝】
paint.drawText(0,50, "Hi");
paint.end();

在这个例子中,p1和p2共享数据,直到对p2调用QPainter::begin(),因为绘制像素图会修改它。

 

警告】:在使用stl风格的迭代器时,要小心复制隐式共享容器(QMap、QVector等)。参见隐式共享迭代器问题

 

隐式共享类列表

 

posted @ 2023-08-05 22:06  远方是什么样子  阅读(29)  评论(0编辑  收藏  举报