隐式共享

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 .

概述

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.

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.

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 mostly takes place behind the scenes; the programmer rarely needs to worry about it. However, Qt's container iterators have different behavior than those from the STL. Read 隐式共享迭代器问题 .

In multithreaded applications, implicit sharing takes place, as explained in 线程和隐式共享类 .

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

隐式共享细节

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 control of its internal data. In any member functions that modify its data, it automatically detaches before modifying the data. Notice, however, the special case with container iterators; see 隐式共享迭代器问题 .

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

代码片段:

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
    }
}
							

类列表

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.

范例:

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 and p2 共享数据直到 QPainter::begin () is called for p2 ,因为描绘像素图会修改它。

警告: Be careful with copying an implicitly shared container ( QMap , QList , etc.) while you use STL 样式迭代器 。见 隐式共享迭代器问题 .

QBitArray

位数组

QBitmap

单色 (1 位深度) 像素图

QBrush

定义 QPainter 绘制形状的填充图案

QByteArray

字节数组

QByteArrayList

字节数组列表

QByteArrayView

带有只读 QByteArray API 子集的字节数组视图

QCache

提供缓存的模板类

QCollator

根据本地整理算法比较字符串

QCollatorSortKey

可以被用于加速字符串整理

QCommandLineOption

定义可能的命令行选项

QContiguousCache

提供连续缓存的模板类

QCursor

具有任意形状的鼠标光标

QDBusPendingCall

引用一待决异步调用

QDBusUnixFileDescriptor

保持一 Unix 文件描述符

QDateTime

日期和时间功能

QDebug

调试信息输出流

QDir

访问目录结构及其内容

QDnsDomainNameRecord

存储有关域名记录的信息

QDnsHostAddressRecord

存储有关主机地址记录的信息

QDnsMailExchangeRecord

存储有关 DNS MX 记录的信息

QDnsServiceRecord

存储有关 DNS SRV 记录的信息

QDnsTextRecord

存储有关 DNS TXT 记录的信息

QFileInfo

与系统无关的文件信息

QFont

指定用于绘制文本的字体查询

QFontInfo

有关字体的一般信息

QFontMetrics

字体规格信息

QFontMetricsF

字体规格信息

QGlyphRun

直接访问字体中的内部字形

QGradient

用于组合 QBrush 以指定渐变填充

QHash

提供基于哈希表的字典的模板类

QHostAddress

IP 地址

QHttp2Configuration

控制 HTTP/2 参数和设置

QHttpPart

保持本体部分 (要在 HTTP 多部分 MIME 消息内使用)

QIcon

在不同模式和状态下的可缩放图标

QImage

独立于硬件的图像表示 (允许直接访问像素数据,且可以被用作描绘设备)

QJsonArray

封装 JSON 数组

QJsonDocument

读写 JSON 文档的办法

QJsonObject

封装 JSON 对象

QJsonParseError

用于在 JSON 剖析期间报告错误

QJsonValue

把值封装在 JSON 中

QKeySequence

封装作为快捷键使用的键序列

QLinkedList

提供链接列表的模板类

QList

提供动态数组的模板类

QLocale

在数字及其各种语言的字符串表示之间转换

QMap

提供关联数组的模板类

QMimeType

描述由 MIME 类型字符串表示的文件或数据的类型

QMqttTopicFilter

Represents a MQTT topic filter

QMqttTopicName

Represents a MQTT topic name

QMultiHash

提供多值哈希的方便 QHash 子类

QMultiMap

提供具有多个等效键的关联数组的模板类

QNetworkAddressEntry

存储由网络接口支持的一个 IP 地址及其关联的 Netmask (网络掩码) 和广播地址

QNetworkCacheMetaData

缓存信息

QNetworkCookie

保持一网络 Cookie

QNetworkInterface

主机的 IP 地址和网络接口列表

QNetworkProxy

网络层代理

QNetworkProxyQuery

用于查询套接字的代理设置

QNetworkRequest

保持要采用 QNetworkAccessManager 发送的请求

QOpenGLDebugMessage

包裹 OpenGL 调试消息

QPageRanges

表示页面范围的集合

QPainterPath

用于描绘操作的容器,使图形形状能够被构造和重用

QPalette

包含用于各 Widget 状态的颜色组

QPen

定义 QPainter 如何绘制线条和形状的轮廓

QPersistentModelIndex

用于在数据模型中定位数据

QPicture

用于记录和重演 QPainter 命令的描绘设备

QPixmap

可以用作描绘设备的离屏图像表示

QPolygon

使用整数精度的点列表

QPolygonF

使用浮点精度的点列表

QProcessEnvironment

保持可以被传递给程序的环境变量

QQueue

提供队列的通用容器

QRawFont

访问字体的单物理实例

QRegExp

使用正则表达式进行模式匹配

QRegion

为描绘器指定裁剪区域

QRegularExpression

使用正则表达式进行模式匹配

QRegularExpressionMatch

QRegularExpression 针对字符串进行匹配的结果

QRegularExpressionMatchIterator

QRegularExpression 对象针对字符串的全局匹配结果迭代器

QSet

提供基于哈希表的集的模板类

QSqlField

操纵 SQL 数据库表和视图中的字段

QSqlQuery

执行和操纵 SQL 语句的手段

QSqlRecord

封装数据库记录

QSslCertificate

用于 X509 证书的便捷 API

QSslCertificateExtension

用于访问 X509 证书扩展名的 API

QSslCipher

表示 SSL 加密密码

QSslConfiguration

保持 SSL 连接的配置和状态

QSslDiffieHellmanParameters

用于服务器的 Diffie-Hellman 参数的接口

QSslError

SSL 错误

QSslKey

用于私钥和公钥的接口

QSslPreSharedKeyAuthenticator

用于 PSK (预共享密钥) 密码套件的身份验证数据

QStack

提供堆栈的模板类

QStaticText

当文本及其布局很少更新时,启用优化文本绘制

QStorageInfo

提供有关当前挂载的存储和驱动器的信息

QString

Unicode 字符串

QStringList

字符串列表

QTextBlockFormat

用于 QTextDocument 文本块的格式化信息

QTextBoundaryFinder

在字符串中查找 Unicode 文本边界的办法

QTextCharFormat

用于 QTextDocument 字符的格式化信息

QTextCursor

提供访问和修改 QTextDocument 的 API

QTextDocumentFragment

表示一块来自 QTextDocument 的格式化文本

QTextFormat

用于 QTextDocument 的格式化信息

QTextFrameFormat

用于 QTextDocument 框架的格式化信息

QTextImageFormat

用于 QTextDocument 图像的格式化信息

QTextListFormat

用于 QTextDocument 列表的格式化信息

QTextTableCellFormat

用于 QTextDocument 中表格单元格的格式化信息

QTextTableFormat

用于 QTextDocument 中表格的格式化信息

QUrl

用于操控 URL 的方便接口

QUrlQuery

在 URL 的查询中操纵键/值对的方法

QVariant

举动像最常见 Qt 数据类型的并集