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 , QList ,等) 当使用 STL 样式迭代器 。见 隐式共享迭代器问题 .
位数组 | |
单色 (1 位深度) 像素图 | |
定义 QPainter 绘制形状的填充图案 | |
字节数组 | |
字节数组列表 | |
带有只读 QByteArray API 子集的字节数组视图 | |
提供缓存的模板类 | |
根据本地整理算法比较字符串 | |
可以用于加速字符串整理 | |
定义可能的命令行选项 | |
提供连续缓存的模板类 | |
具有任意形状的鼠标光标 | |
引用一待决异步调用 | |
保持一 Unix 文件描述符 | |
日期和时间功能 | |
调试信息输出流 | |
访问目录结构及其内容 | |
存储域名记录的有关信息 | |
存储有关主机地址记录的信息 | |
存储有关 DNS MX 记录的信息 | |
存储有关 DNS SRV 记录的信息 | |
存储有关 DNS TXT 记录的信息 | |
OS-independent API to retrieve information about file system entries | |
指定用于绘制文本的字体查询 | |
有关字体的一般信息 | |
字体规格信息 | |
字体规格信息 | |
表示接近要监视区域或地区的参数 | |
包含特定时间点的全局位置、方向和速度的有关聚合信息 | |
包含有关卫星的基本信息 | |
直接访问字体中的内部字形 | |
用于组合 QBrush 以指定渐变填充 | |
提供基于哈希表的字典的模板类 | |
IP 地址 | |
控制 HTTP/1 参数和设定 | |
控制 HTTP/2 参数和设定 | |
保持本体部分 (要在 HTTP 多部分 MIME 消息内使用) | |
在不同模式和状态下的可伸缩图标 | |
独立于硬件的图像表示 (允许直接访问像素数据,且可以被用作描绘设备) | |
封装 JSON 数组 | |
读写 JSON 文档的办法 | |
封装 JSON 对象 | |
用于在 JSON 剖析期间报告错误 | |
把值封装在 JSON 中 | |
封装作为快捷键使用的键序列 | |
提供链接列表的模板类 | |
提供动态数组的模板类 | |
在数字及其各种语言的字符串表示之间转换 | |
表示蓝牙低功耗广告期间要广播的数据 | |
表示用于蓝牙低功耗广告的参数 | |
用于设置 GATT 服务数据 | |
当请求或报告蓝牙 LE 连接的参数更新时使用 | |
用于创建 GATT 服务数据 | |
用于设置 GATT 服务数据 | |
提供关联数组的模板类 | |
描述由 MIME 类型字符串表示的文件或数据的类型 | |
表示 MQTT 话题过滤 | |
表示 MQTT 话题名称 | |
提供多值哈希的方便 QHash 子类 | |
提供具有多个等效键的关联数组的模板类 | |
存储由网络接口支持的一个 IP 地址及其关联的 Netmask (网络掩码) 和广播地址 | |
缓存信息 | |
保持一网络 Cookie | |
主机的 IP 地址和网络接口列表 | |
网络层代理 | |
用于查询套接字的代理设置 | |
保持要采用 QNetworkAccessManager 发送的请求 | |
Convenience class for grouping remote server endpoints that share common network request properties | |
包裹 OpenGL 调试消息 | |
表示页面范围的集合 | |
用于描绘操作的容器,使图形形状能够被构造和重用 | |
包含各 Widget 状态的颜色组 | |
定义 QPainter 如何绘制线条和形状的轮廓 | |
用于在数据模型中定位数据 | |
用于记录和重演 QPainter 命令的描绘设备 | |
可以用作描绘设备的离屏图像表示 | |
使用整数精度的点列表 | |
使用浮点精度的点列表 | |
保持可以被传递给程序的环境变量 | |
提供队列的通用容器 | |
访问字体的单物理实例 | |
使用正则表达式进行模式匹配 | |
为描绘器指定裁剪区域 | |
使用正则表达式进行模式匹配 | |
QRegularExpression 针对字符串进行匹配的结果 | |
QRegularExpression 对象针对字符串的全局匹配结果迭代器 | |
提供基于哈希表的集的模板类 | |
操纵 SQL 数据库表和视图中的字段 | |
执行和操纵 SQL 语句的手段 | |
封装数据库记录 | |
用于 X509 证书的便捷 API | |
用于访问 X509 证书扩展名的 API | |
表示 SSL 加密密码 | |
保持 SSL 连接的配置和状态 | |
用于服务器的 Diffie-Hellman 参数的接口 | |
SSL 错误 | |
用于私钥和公钥的接口 | |
用于 PSK (预共享密钥) 密码套件的身份验证数据 | |
提供堆栈的模板类 | |
当文本及其布局很少更新时,启用优化文本绘制 | |
提供有关当前挂载的存储和驱动器的信息 | |
Unicode 字符串 | |
字符串列表 | |
用于 QTextDocument 文本块的格式化信息 | |
在字符串中查找 Unicode 文本边界的办法 | |
用于 QTextDocument 字符的格式化信息 | |
提供访问和修改 QTextDocument 的 API | |
表示一块来自 QTextDocument 的格式化文本 | |
用于 QTextDocument 的格式化信息 | |
用于 QTextDocument 框架的格式化信息 | |
用于 QTextDocument 图像的格式化信息 | |
用于 QTextDocument 列表的格式化信息 | |
用于 QTextDocument 中表格单元格的格式化信息 | |
用于 QTextDocument 中表格的格式化信息 | |
用于操控 URL 的方便接口 | |
在 URL 的查询中操纵键/值对的方法 | |
举动像最常见 Qt 数据类型的并集 |