QT隐式共享
Qt 中许多 C++ 类使用隐式数据共享来最大程度地利用资源并最小化复制。隐式共享类在作为参数传递时既安全又高效,因为只传递数据的指针,只有在函数写入数据时才会复制数据,即写时复制。
概述
共享类由指向包含引用计数和数据的共享数据块的指针组成。
创建共享对象时,将引用计数设置为 1。每当新对象引用共享数据时,引用计数增加,当对象取消引用共享数据时,引用计数减少。当引用计数变为零时,共享数据被删除。
处理共享对象时,有两种复制对象的方式。通常我们谈论深复制和浅复制。深复制意味着复制对象。浅复制是一个引用复制,即只是一个指向共享数据块的指针。进行深复制可能会导致内存和 CPU 方面的昂贵。进行浅复制非常快,因为它只涉及设置指针和增加引用计数。
隐式共享对象的对象赋值(使用 operator=())是使用浅复制实现的。
共享的好处在于程序不需要不必要地复制数据,这导致内存使用较低且数据复制较少。对象可以轻松分配、作为函数参数传递和从函数返回。
隐式共享大多数时候都在幕后进行,程序员很少需要担心它。但是,Qt 的容器迭代器与 STL 的容器迭代器有不同的行为。请阅读 隐式共享迭代器问题。
在多线程应用程序中,隐式共享会发生,详细信息请参阅 线程和隐式共享类。
当您实现自己的隐式共享类时,请使用 QSharedData 和 QSharedDataPointer 类。
隐式共享详解
如果对象即将更改且引用计数大于一,则隐式共享会自动将对象与共享块分离。(这通常称为写时复制或值语义。)
隐式共享类控制其内部数据。在任何修改数据的成员函数中,在修改数据之前,它会自动分离数据。但请注意,容器迭代器有一个特殊情况;请参阅 隐式共享迭代器问题。
使用隐式共享的 QPen 类在所有更改内部数据的成员函数中都会从共享数据中分离出来。
代码片段:
void QPen::setStyle(Qt::PenStyle style)
{
detach(); // 从公共数据中分离
d->style = style; // 设置样式成员
}
void QPen::detach()
{
if (d->ref != 1) {
... // 执行深度复制
}
}
类列表
如果对象即将更改,则下面列出的类会自动从公共数据中分离。程序员甚至不会注意到对象是共享的。因此,您应该将它们的不同实例视为单独的对象。它们始终会被视为单独的对象,但是具有在可能的情况下共享数据的额外好处。因此,您可以将这些类的实例作为值传递给函数的参数,而不必担心复制开销。
示例:
QPixmap p1, p2;
p1.load("image.bmp");
p2 = p1; // p1 和 p2 共享数据
QPainter paint;
paint.begin(&p2); // 从 p1 中分离 p2
paint.drawText(0,50, "Hi");
paint.end();
在此示例中,和会共享数据,直到调用 QPainter::begin() 为止,因为绘制像素图会修改它。p1、p2 和 p2
警告: 在使用 STL 风格迭代器 时,复制隐式共享容器(QMap、QVector 等)时要小心。请参阅 隐式共享迭代器问题。
英文 | 中文 |
---|---|
QBitArray | 位数组 |
QBitmap | 单色(1 位深度)位图 |
QBrush | QPainter 绘制的形状的填充模式定义 |
QByteArray | 字节数组 |
QByteArrayList | 字节数组列表 |
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 | 封装了快捷键中使用的键序列 |
QList | 提供列表的模板类 |
QLocale | 在各种语言之间转换数字及其字符串表示 |
QMap | 提供基于红黑树的字典的模板类 |
QMimeType | 描述文件或数据类型的 MIME 类型字符串 |
QMultiHash | 提供多值哈希的便利 QHash 子类 |
QMultiMap | 提供多值映射的便利 QMap 子类 |
QNetworkAddressEntry | 存储由网络接口支持的一个 IP 地址,以及其关联的子网掩码和广播地址 |
QNetworkCacheMetaData | 缓存信息 |
QNetworkCookie | 包含一个网络 cookie |
QNetworkInterface | 主机的 IP 地址和网络接口列表 |
QNetworkProxy | 网络层代理 |
QNetworkProxyQuery | 用于查询套接字的代理设置 |
QNetworkRequest | 保存要与 QNetworkAccessManager 发送的请求 |
QOpenGLDebugMessage | 封装了 OpenGL 调试消息 |
QPainterPath | 绘图操作的容器,使得可以构造和重用图形形状 |
QPalette | 包含每个小部件状态的颜色组 |
QPen | 定义 QPainter 如何绘制线条和形状的轮廓 |
QPersistentModelIndex | 用于定位数据模型中的数据 |
QPicture | 记录和重播 QPainter 命令的绘图设备 |
QPixmap | 可用作绘图设备的屏幕外图像表示 |
QPolygon | 使用整数精度的点的向量 |
QPolygonF | 使用浮点精度的点的向量 |
QProcessEnvironment | 保存可以传递给程序的环境变量 |
QQueue | 提供队列的通用容器 |
QRawFont | 访问字体的单个物理实例 |
QRegExp | 使用正则表达式进行模式匹配 |
QRegion | 为 QPainter 指定剪辑区域 |
QRegularExpression | 使用正则表达式进行模式匹配 |
QRegularExpressionMatch | 对 QRegularExpression 与字符串进行匹配的结果 |
QRegularExpressionMatchIterator | 针对 QRegularExpression 对象与字符串的全局匹配结果的迭代器 |
QSet | 提供基于哈希表的集合的模板类 |
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 | 提供访问和修改 QTextDocuments 的 API |
QTextDocumentFragment | 表示来自 QTextDocument 的格式化文本片段 |
QTextFormat | QTextDocument 的格式信息 |
QTextFrameFormat | QTextDocument 中框架的格式信息 |
QTextImageFormat | QTextDocument 中图像的格式信息 |
QTextListFormat | QTextDocument 中列表的格式信息 |
QTextTableCellFormat | QTextDocument 中表格单元格的格式信息 |
QTextTableFormat | QTextDocument 中表格的格式信息 |
QUrl | 用于处理 URL 的便捷接口 |
QUrlQuery | 在 URL 的查询中操作键值对的方式 |
QVariant | 对最常见的 Qt 数据类型起到联合作用 |
QVector | 提供动态数组的模板类 |