隐式共享

Qt 中的很多 C++ 类使用隐式数据共享,以最大化利用资源并最小化拷贝。隐式共享类既安全又高效当作为参数传递时,因为仅传递指向数据的指针,且仅当函数写入时才拷贝数据,即 写入时拷贝 .

概述

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

当创建共享对象时,它将引用计数设为 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.

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 线程和隐式共享类 .

当实现自己的隐式共享类时,使用 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 写入时拷贝 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 隐式共享迭代器问题 .

The 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 () 被调用对于 p2 ,因为描绘像素图会修改它。

警告: 小心拷贝隐式共享容器 ( QMap , QVector ,等) 当使用 STL 样式迭代器 。见 隐式共享迭代器问题 .

QDebug 调试信息输出流
QDir 访问目录结构及其内容
QFileInfo 与系统无关的文件信息
QProcessEnvironment 保持可以被传递给程序的环境变量
QStorageInfo 提供有关当前挂载的存储和驱动器的信息
QUrl 用于操控 URL 的方便接口
QUrlQuery 在 URL 的查询中操纵键/值对的方法
QPersistentModelIndex 用于在数据模型中定位数据
QJsonArray 封装 JSON 数组
QJsonDocument 读写 JSON 文档的办法
QJsonParseError 用于在 JSON 剖析期间报告错误
QJsonObject 封装 JSON 对象
QJsonValue 把值封装在 JSON 中
QVariant 举动像最常见 Qt 数据类型的并集
QMimeType 描述由 MIME 类型字符串表示的文件或数据的类型
QBitArray 位数组
QByteArray 字节数组
QByteArrayList 字节数组列表
QCache 提供缓存的模板类
QCollator 根据本地整理算法比较字符串
QCollatorSortKey 可以用于加速字符串整理
QCommandLineOption 定义可能的命令行选项
QContiguousCache 提供连续缓存的模板类
QDateTime 日期和时间功能
QHash 提供基于哈希表的字典的模板类
QMultiHash 提供多值哈希的方便 QHash 子类
QLinkedList 提供链接列表的模板类
QList 提供列表的模板类
QLocale 在数字及其各种语言的字符串表示之间转换
QMap 提供基于红-黑-树的字典的模板类
QMultiMap 提供多值映射的方便 QMap 子类
QQueue 提供队列的通用容器
QRegExp 使用正则表达式进行模式匹配
QRegularExpression 使用正则表达式进行模式匹配
QRegularExpressionMatch QRegularExpression 针对字符串进行匹配的结果
QRegularExpressionMatchIterator QRegularExpression 对象针对字符串的全局匹配结果迭代器
QSet 提供基于哈希表的集的模板类
QStack 提供堆栈的模板类
QString Unicode 字符串
QStringList 字符串列表
QTextBoundaryFinder 在字符串中查找 Unicode 文本边界的办法
QVector 提供动态数组的模板类
QDBusPendingCall 引用一待决异步调用
QDBusUnixFileDescriptor 保持一 Unix 文件描述符
QBitmap 单色 (1 位深度) 像素图
QIcon 在不同模式和状态下的可伸缩图标
QImage 独立于硬件的图像表示 (允许直接访问像素数据,且可以被用作描绘设备)
QPicture 用于记录和重演 QPainter 命令的描绘设备
QPixmap 可以用作描绘设备的离屏图像表示
QCursor 具有任意形状的鼠标光标
QKeySequence 封装作为快捷键使用的键序列
QPalette 包含各 Widget 状态的颜色组
QOpenGLDebugMessage 包裹 OpenGL 调试消息
QBrush 定义 QPainter 绘制形状的填充图案
QGradient 用于组合 QBrush 以指定渐变填充
QPainterPath 用于描绘操作的容器,使图形形状能够被构造和重用
QPen 定义 QPainter 如何绘制线条和形状的轮廓
QPolygon Vector of points using integer precision
QPolygonF Vector of points using floating point precision
QRegion 为描绘器指定裁剪区域
QFont Specifies a font used for drawing text
QFontInfo 有关字体的一般信息
QFontMetrics 字体规格信息
QFontMetricsF 字体规格信息
QGlyphRun 直接访问字体中的内部字形
QRawFont 访问字体的单物理实例
QStaticText 当文本及其布局很少更新时,启用优化文本绘制
QTextCursor 提供访问和修改 QTextDocument 的 API
QTextDocumentFragment 表示一块来自 QTextDocument 的格式化文本
QTextBlockFormat 用于 QTextDocument 文本块的格式化信息
QTextCharFormat 用于 QTextDocument 字符的格式化信息
QTextFormat 用于 QTextDocument 的格式化信息
QTextFrameFormat 用于 QTextDocument 框架的格式化信息
QTextImageFormat 用于 QTextDocument 图像的格式化信息
QTextListFormat 用于 QTextDocument 列表的格式化信息
QTextTableCellFormat 用于 QTextDocument 中表格单元格的格式化信息
QTextTableFormat 用于 QTextDocument 中表格的格式化信息
QNetworkCacheMetaData 缓存信息
QHttpPart 保持本体部分 (要在 HTTP 多部分 MIME 消息内使用)
QNetworkCookie 保持一网络 Cookie
QNetworkRequest 保持要采用 QNetworkAccessManager 发送的请求
QNetworkConfiguration 一个或多个访问点配置的抽象
QDnsDomainNameRecord 存储域名记录的有关信息
QDnsHostAddressRecord 存储有关主机地址记录的信息
QDnsMailExchangeRecord 存储有关 DNS MX 记录的信息
QDnsServiceRecord 存储有关 DNS SRV 记录的信息
QDnsTextRecord 存储有关 DNS TXT 记录的信息
QHostAddress IP 地址
QNetworkAddressEntry 存储由网络接口支持的一个 IP 地址及其关联的 Netmask (网络掩码) 和广播地址
QNetworkInterface 主机的 IP 地址和网络接口列表
QNetworkProxy 网络层代理
QNetworkProxyQuery 用于查询套接字的代理设置
QSslCertificate 用于 X509 证书的便捷 API
QSslCertificateExtension 用于访问 X509 证书扩展名的 API
QSslCipher 表示 SSL 加密密码
QSslConfiguration 保持 SSL 连接的配置和状态
QSslDiffieHellmanParameters 用于服务器的 Diffie-Hellman 参数的接口
QSslError SSL 错误
QSslKey 用于私钥和公钥的接口
QSslPreSharedKeyAuthenticator 用于 PSK (预共享密钥) 密码套件的身份验证数据
QSqlField 操纵 SQL 数据库表和视图中的字段
QSqlQuery 执行和操纵 SQL 语句的手段
QSqlRecord 封装数据库记录
QLowEnergyAdvertisingData 表示蓝牙低功耗广告期间要广播的数据
QLowEnergyAdvertisingParameters 表示用于蓝牙低功耗广告的参数
QLowEnergyCharacteristicData 用于设置 GATT 服务数据
QLowEnergyConnectionParameters 当请求或报告蓝牙 LE 连接的参数更新时使用
QLowEnergyDescriptorData 用于创建 GATT 服务数据
QLowEnergyServiceData 用于设置 GATT 服务数据