隐式共享
Qt 中的许多 C++ 类都采用隐式数据共享机制,以最大限度地利用资源并减少复制操作。当作为参数传递时,隐式共享类既安全又高效,因为传递的只是数据的指针,只有当函数需要向数据写入时才会进行复制,即“写时复制”(copy-on-write)机制。
概述
共享类由一个指向共享数据块的指针组成,该数据块包含引用计数和数据本身。
创建共享对象时,会将引用计数设置为 1。每当有新对象引用该共享数据时,引用计数就会递增;当该对象解除对共享数据的引用时,引用计数就会递减。当引用计数变为零时,共享数据将被删除。
在处理共享对象时,有两种复制对象的方法。我们通常称之为深拷贝和浅拷贝。深拷贝意味着复制对象本身。 浅拷贝则是引用拷贝,即仅复制指向共享数据块的指针。进行深拷贝在内存和 CPU 消耗方面可能较为昂贵。而浅拷贝则非常快速,因为它仅涉及设置指针和递增引用计数。
对于隐式共享的对象,其对象赋值(使用 operator=()) 是通过浅拷贝实现的。
共享的优势在于,程序无需不必要地复制数据,从而降低了内存占用并减少了数据复制操作。对象可以轻松地进行赋值、作为函数参数传递,以及从函数中返回。
隐式共享大多在后台进行;程序员很少需要担心它。然而,Qt 的容器迭代器与 STL 中的行为不同。请阅读《隐式共享迭代器问题》。
在多线程应用程序中,会发生隐式共享,具体说明请参阅《线程与隐式共享类》。
在实现自己的隐式共享类时,请使用QSharedData 和QSharedDataPointer 类。
隐式共享详解
如果对象即将发生变化且引用计数大于一,隐式共享会自动将该对象从共享块中分离出来。(这通常被称为“写时复制”或“值语义”。)
隐式共享类对其内部数据具有控制权。在任何会修改其数据的成员函数中,该类会在修改数据之前自动脱离共享块。但请注意容器迭代器的特殊情况;参见“隐式共享迭代器问题”。
QPen 类采用隐式共享机制,在所有会修改内部数据的成员函数中,都会与共享数据解除关联。
代码片段:
void QPen::setCapStyle(Qt::PenCapStyle c)
{
if (d->capStyle == c)
return;
detach();
d->capStyle = c;
}
void QPen::detach()
{
d.detach();
}类列表
如果某个对象即将被修改,下面列出的类会自动与共享数据脱离关联。 程序员甚至不会察觉到这些对象是共享的。因此,您应将它们的各个实例视为独立的对象。它们始终会表现为独立的对象,同时还能在可能的情况下共享数据。正因如此,您可以将这些类的实例作为按值传递的参数传给函数,而无需担心复制开销。
示例:
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 和p2 共享数据,直到为p2 调用QPainter::begin()时为止,因为绘制像素图会对其进行修改。
警告: 在使用STL 风格迭代器时,请 谨慎复制隐式共享的容器(如QMap 、QList 等)。请参阅“隐式共享迭代器问题”。
位数组 | |
单色(1 位深度)位图 | |
定义由 QPainter 绘制的形状的填充模式 | |
字节数组 | |
字节数组列表 | |
通过 QByteArray API 的只读子集访问字节数组 | |
提供缓存的模板类 | |
根据本地化的排序算法比较字符串 | |
可用于加快字符串排序速度 | |
定义了一个可能的命令行选项 | |
提供连续缓存的模板类 | |
具有任意形状的鼠标光标 | |
指一个待处理的异步调用 | |
持有一个 Unix 文件描述符 | |
日期和时间函数 | |
用于调试信息的输出流 | |
访问目录结构及其内容 | |
存储有关域名记录的信息 | |
存储有关主机地址记录的信息 | |
存储有关 DNS MX 记录的信息 | |
存储有关 DNS SRV 记录的信息 | |
存储有关 DNS TXT 记录的信息 | |
存储有关 DNS TLSA 记录的信息 | |
用于检索文件系统条目信息的操作系统无关 API | |
指定用于绘制文本的字体的查询 | |
关于字体的通用信息 | |
字体度量信息 | |
字体度量信息 | |
表示字体中的一个可变轴 | |
用于简化 QHttpMultiPart 对象构建的便捷类 | |
用于简化 QHttpPart 对象构建的便捷类 | |
描述了用于监测邻近性的区域或范围的参数 | |
包含在特定时间点收集的全球位置、方向和速度信息 | |
包含有关卫星的基本信息 | |
直接访问字体中的内部字形 | |
与 QBrush 结合使用,用于指定渐变填充 | |
提供基于哈希表的字典的模板类 | |
IP 地址 | |
控制 HTTP/1 参数和设置 | |
控制 HTTP/2 参数和设置 | |
保存用于 HTTP 多部分 MIME 消息中的正文部分 | |
可在不同模式和状态下缩放的图标 | |
一种与硬件无关的图像表示形式,允许直接访问像素数据,并可作为绘图设备使用 | |
封装一个 JSON 数组 | |
读写 JSON 文档的方法 | |
封装一个 JSON 对象 | |
用于报告 JSON 解析过程中的错误 | |
封装 JSON 中的值 | |
封装快捷键所使用的键序列 | |
提供链表功能的模板类 | |
提供动态数组的模板类 | |
在各种语言中实现数字与其字符串表示形式之间的转换 | |
表示在蓝牙低功耗(BLE)广告期间要广播的数据 | |
表示用于蓝牙低功耗(BLE)广告的参数 | |
用于配置 GATT 服务数据 | |
用于请求或报告蓝牙低功耗连接参数的更新 | |
用于创建 GATT 服务数据 | |
用于设置 GATT 服务数据 | |
提供关联数组的模板类 | |
描述文件或数据类型,由 MIME 类型字符串表示 | |
表示一个 MQTT 主题过滤器 | |
表示一个 MQTT 主题名称 | |
多值哈希表 | |
提供具有多个等效键的关联数组的模板类 | |
存储网络接口支持的一个 IP 地址,以及与其关联的子网掩码和广播地址 | |
缓存信息 | |
保存一个网络 Cookie | |
主机 IP 地址和网络接口列表 | |
网络层代理 | |
用于查询套接字的代理设置 | |
保存一个将通过 QNetworkAccessManager 发送的请求 | |
用于将具有共同网络请求属性的远程服务器端点分组的便捷类 | |
封装 OpenGL 调试消息 | |
表示一组页面范围 | |
包含每个控件状态对应的颜色组 | |
定义 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 数据类型的联合体 |
© 2026 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.