Qt中的"隐式共享"

34 篇文章 0 订阅

一个共享类对象创建,它的引用计数就记为1,如果将它传递给另一个对象,那计数就加1,并两个对象都指向内存中的相同的内部数据结构。如果某一个修改了对象值就会发生深度复制,以确保他们指向的数据结构不相同。并且之前的数据计数将减1,修改后的数据计数就为1。为1表示没有被共享。

这里简单讲下深度复制和浅度复制。


【转】

雷雷的博客


隐式共享

  (2013-10-12 16:58:22)
标签: 

365

分类: QT

Qt Implicit Sharing (隐式共享)



转(http://hi.baidu.com/wolfand11/item/fdccbc5099e584adacc857d9
今天翻译了以下Qt文档中关于隐式共享的叙述,在此记录下来供以后查看。由于我水平有限(英语四级依然没过),所以大家谨慎参考。如有高手请指正其中错误,谢谢

Implicit Sharing
隐式共享

Many C++ classes in Qt use implicit data sharing to maximize resource usage and minimize copying. Implicitly shared classes are both safe and efficient when passed as arguments, because only a pointer to the data is passed around, and the data is copied only if and when a function writes to it, i.e., copy-on-write.

Qt中的很多C++类通过使用隐式数据共享来最大化资源的使用效率和最小化复制的资源耗费。将隐
式共享类作为参数传递不仅安全而且效率高,因为在这个过程中只有指向这个数据的指针被传递,
并且当且仅当有函数对这个数据进行写操作时,才会对该数据进行复制。

Overview
Implicit Sharing in Detail
List of Classes
Overview

A shared class consists of a pointer to a shared data block that contains a reference count and the data.

一个共享类包括一个指向一个共享数据块的指针,共享数据块由数据和对共享数据进行引用的数目。

When a shared object is created, it sets the reference count to 1. The reference count is incremented whenever a new object references the shared data, and decremented when the object dereferences the shared data. The shared data is deleted when the reference count becomes zero.

当一个共享对象被创建时,共享数据的引用数目会被设置为1.无论何时,只要有一个新的对象引用该
共享数据,该共享数据对应的这个引用数目都会加一,相反,若有对象不再引用该共享数据时,其对
应的引用数目将会减一。当共享数据的引用数目为0时,该共享数据就会被撤销掉。

When dealing with shared objects, there are two ways of copying an object. We usually speak about deep and shallow copies. A deep copy implies duplicating an object. A shallow copy is a reference copy, i.e. just a pointer to a shared data block. Making a deep copy can be expensive in terms of memory and CPU. Making a shallow copy is very fast, because it only involves setting a pointer and incrementing the reference count.

当处理共享对象时,有两种方法来复制一个对象。我们常常将其称为深拷贝和浅拷贝。深拷贝会隐式的
复制一个对象。而钱拷贝只是引用的复制,即只是一个指向共享数据块的指针的复制。做一次深拷贝
会占用很大的内存和CPU资源。然而,做一次浅拷贝则很快,因为那仅仅需要处理指针的设置和引用数目
的增加。


Object assignment (with operator=()) for implicitly shared objects is implemented using shallow copies.

隐式共享对象的赋值是通过浅拷贝来实现的。

The benefit of sharing is that a program does not need to duplicate data unnecessarily, which results in lower memory use and less copying of data. Objects can easily be assigned, sent as function arguments, and returned from functions.

共享的好处是程序不需要对数据进行不必要的复制,这样就降低了内存的使用并且减少了数据的复制。
对象可以容易地被复制,作为函数的参数传递,作为函数的返回值。

Implicit sharing takes place behind the scenes; the programmer does not need to worry about it. Even in multithreaded applications, implicit sharing takes place, as explained in Threads and Implicitly Shared Classes.

隐式共享发生在场景背后,程序员不必担心它。甚至在多线程应用程序中,隐式共享也会像在多线程和隐式共享类中描述
的那样发生。

When implementing your own implicitly shared classes, use the QSharedData and QSharedDataPointer classes.

但要实现你自己的隐式共享类时,可以使用QSharedData和QSharedDataPointer这两个类。

Implicit Sharing in Detail

隐式共享的细节

Implicit sharing automatically detaches the object from a shared block if the object is about to change and the reference count is greater than one. (This is often called copy-on-write or value semantics.)

如果对象即将改变或引用数目大于一时,隐式共享会自动从共享的块上脱离着个对象。(这通常被称为写时拷贝或值语义)

An implicitly shared class has total control of its internal data. In any member functions that modify its data, it automatically detaches before modifying the data.

一个隐式共享类有他内部数据的总控制。在任何成员函数中修改它的数据,它将在数据修改之前,自动脱离共享数据块。

The QPen class, which uses implicit sharing, detaches from the shared data in all member functions that change the internal data.

QPen 类就是一个隐式共享类。在所有修改内部数据的成员函数中,它会脱离共享数据。

Code fragment:

代码片段:

void QPen::setStyle(Qt::PenStyle style)
{
detach();                     // detach from common data   从共享数据中脱离
d->style = style;     // set the style member               设置style数据成员
}

void QPen::detach()
{
if (d->ref != 1) {
...                         // perform a deep copy   进行一次深拷贝
}
}
List of Classes

类列表

The classes listed below automatically detach from common data if an object is about to be changed. The programmer will not even notice that the objects are shared. Thus you should treat separate instances of them as separate objects. They will always behave as separate objects but with the added benefit of sharing data whenever possible. For this reason, you can pass instances of these classes as arguments to functions by value without concern for the copying overhead.

下面的类列表中,如果他们的对象将要改变时,对象将会从共享数据脱离。程序员甚至没注意到对象是共享数据的。那样你应该
把他们单独的实例当作单独的对象。他们总是表现的像单独的对象一样,但是只要有可能就依然存在添加的数据共享的好处。这
样,你可以通过值将这些类的实例作为参数传递给函数,而不必关心复制的总开销。

Example:

例如:

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 自动脱离共享数据。
paint.drawText(0,50, "Hi");
paint.end();
In this example, p1 and p2 share data until QPainter::begin() is called for p2, because painting a pixmap will modify it.

在这个例子中,p1 和 p2 共享数据,直到为p2调用函数QPainter::begin() ,因为画一副图将会改变这幅图。

Warning: Do not copy an implicitly shared container (QMap, QVector, etc.) while you are iterating over it using an non-const STL-style iterator.

警告:当你使用一个非常量STL风格的迭代器在隐式共享容器上进行迭代时,不要复制这个隐式共享的容器(QMap, QVector, 等等)

QBitArray       Array of bits
位数组
QBitmap       Monochrome (1-bit depth) pixmaps
单色的(一位深度)图片
QBrush       Defines the fill pattern of shapes drawn by QPainter
定义用QPainter画出的形状的填充形式
QByteArray       Array of bytes
字节数组
QCache       Template class that provides a cache
提供缓存的模板类
QContiguousCache       Template class that provides a contiguous cache
提供连续的缓存的模板类
QCursor       Mouse cursor with an arbitrary shape
带有任意形状的鼠标
QDir       Access to directory structures and their contents
访问目录的结构和他们的内容
QFileInfo       System-independent file information
系统独立的文件信息
QFont       Specifies a font used for drawing text
指定画文本的字体
QFontInfo       General information about fonts
关于字体的一般信息
QFontMetrics       Font metrics information
字体的韵律信息
QFontMetricsF       Font metrics information
字体的韵律信息
QGLColormap       Used for installing custom colormaps into a QGLWidget
用来向一个QGLWidget安装一个自定义的颜色组
QGradient       Used in combination with QBrush to specify gradient fills
和QBrush结合起来指定填充的渐变风格
QHash       Template class that provides a hash-table-based dictionary
提供一个基于哈希表的目录的模板类
QIcon       Scalable icons in different modes and states
以不同模式和状态伸缩的图标
QImage       Hardware-independent image representation that allows direct access to the pixel data, and can be used as a paint device
硬件独立的图像表示法,允许直接访问像素数据,并且可以用作一个绘画设备。
QKeySequence       Encapsulates a key sequence as used by shortcuts
一个键序列用作快捷键
QLinkedList       Template class that provides linked lists
提供链表的模板类
QList       Template class that provides lists
提供列表的模板类
QLocale       Converts between numbers and their string representations in various languages
在各种各样的语言中转换他们的数字和字符串表示法。
QMap       Template class that provides a skip-list-based dictionary
提供一个基于忽略列表的目录的模板类
QMultiHash       Convenience QHash subclass that provides multi-valued hashes
一个便利的QHash子类提供了多值哈希
QMultiMap       Convenience QMap subclass that provides multi-valued maps
一个便利的QMap子类提供了多值关联
QPainterPath       Container for painting operations, enabling graphical shapes to be constructed and reused
绘画操作的容器,使图画形状可以被构建和被重复利用   
QPalette       Contains color groups for each widget state
包含每个控件状态的颜色组
QPen       Defines how a QPainter should draw lines and outlines of shapes
定义一个a QPainter应该如何画线以及图像的轮廓
QPicture       Paint device that records and replays QPainter commands
绘图设备,可以记录和重演QPainter的命令
QPixmap       Off-screen image representation that can be used as a paint device
屏幕以外的图像表示法可作一个绘图设备
QPolygon       Vector of points using integer precision
整数精确度的点的容器
QPolygonF       Vector of points using floating point precision
浮点数精确度的点的容器
QQueue       Generic container that provides a queue
提供队列的普通容器
QRegExp       Pattern matching using regular expressions
使用正则表达式进行模式匹配
QRegion       Specifies a clip region for a painter
为painer指定一个区域
QSet       Template class that provides a hash-table-based set
提供基于哈希表的集合的模板类
QSqlField       Manipulates the fields in SQL database tables and views
在SQL数据库表和视图中操作领域   
QSqlQuery       Means of executing and manipulating SQL statements
执行和操作SQL语句的方式
QSqlRecord       Encapsulates a database record
浓缩一个数据库记录
QStack       Template class that provides a stack
提供栈的模板类
QString       Unicode character string
Unicode字符编码的字符串
QStringList List of strings
字符串列表
QTextBoundaryFinder       Way of finding Unicode text boundaries in a string
发现一个字符串中Unicode文本边界的方法
QTextCursor       Offers an API to access and modify QTextDocuments
提供一个访问和修改QTextDocuments的应用程序编程接口
QTextDocumentFragment       Represents a piece of formatted text from a QTextDocument
代表从QTextDocument格式化文本的片断
QTextFormat       Formatting information for a QTextDocument
QTextDocument的格式化信息
QUrl       Convenient interface for working with URLs
与URLs一起工作的便利的接口
QVariant       Acts like a union for the most common Qt data types
行为就像一个最普遍的Qt的数据类型的联盟
QVector       Template class that provides a dynamic array
提供动态数组的模板类
QX11Info       Information about the X display configuration
关于X显示配置的信息 


实验:


    QList<QString> lst1;
    lst1.append("123");
    lst1.append("456");
    QList<QString> lst2 = lst1;	// lst1和lst2的地址不一样,是在栈里

// lst1[0]和lst[1]的地址一样

 
    void* c = (void*)&(lst1.at(0));
    void* d = (void*)&(lst2.at(0));
 
    void* a = &lst1[0];		// a的地址变了
    void* b = &lst2[0];
    lst1[0] = "222";		// lst1[0]的地址和值变了, lst2[0]的地址和值没变; lst1和lst2的地址都没变

结果:

lst1和lst2的地址不一样,是在栈里

lst1[0]和lst[1]的地址一样

        c,d,b的地址一样

        a的地址改变了

分析:

        at函数返回const值,所以没有复制

        []操作符返回非const值,所以复制了,不论是读还是写

lst1和lst2的地址都没变

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值