隐式共享

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 隐式共享迭代器问题 .

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 , QList ,等) 当使用 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 字体规格信息
QGeoAreaMonitorInfo 表示接近要监视区域或地区的参数
QGeoPositionInfo 包含特定时间点的全局位置、方向和速度的有关聚合信息
QGeoSatelliteInfo 包含有关卫星的基本信息
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 在数字及其各种语言的字符串表示之间转换
QLowEnergyAdvertisingData 表示蓝牙低功耗广告期间要广播的数据
QLowEnergyAdvertisingParameters 表示用于蓝牙低功耗广告的参数
QLowEnergyCharacteristicData 用于设置 GATT 服务数据
QLowEnergyConnectionParameters 当请求或报告蓝牙 LE 连接的参数更新时使用
QLowEnergyDescriptorData 用于创建 GATT 服务数据
QLowEnergyServiceData 用于设置 GATT 服务数据
QMap 提供关联数组的模板类
QMimeType 描述由 MIME 类型字符串表示的文件或数据的类型
QMqttTopicFilter 表示 MQTT 话题过滤
QMqttTopicName 表示 MQTT 话题名称
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 数据类型的并集