[Qt]QString隐式拷贝

引言

在Qt框架中,QString 作为字符串处理的核心类,其高效的内存管理机制一直是开发者津津乐道的特性。这背后的关键便是 隐式共享(Implicit Sharing),也称为 写时复制(Copy-On-Write, COW)。本文将深入剖析这一机制的原理、优势及注意事项,助你写出更高效的Qt代码。


1. 什么是隐式共享?

隐式共享是Qt的核心设计思想之一,允许多个对象共享同一份数据,直到某个对象尝试修改数据时,才真正执行复制操作。这种机制在保证逻辑独立性的同时,最小化了内存占用和拷贝开销。

核心特点

  • 共享数据:多个QString指向同一内存块。

  • 延迟复制:仅在写入时创建副本。

  • 引用计数:通过计数器跟踪共享状态。


2. 隐式共享的工作原理

2.1 浅拷贝(Shallow Copy)

QString str1 = "Hello";
QString str2 = str1; // 浅拷贝:共享同一数据

此时内存结构:

str1 → [Data: "Hello" | RefCount=2]
str2 ↗

RefCount(引用计数)增至2,无实际数据复制。

2.2 写时复制(Copy-On-Write)

str2[0] = 'h'; // 修改触发深拷贝

修改后的内存结构:

str1 → [Data: "Hello" | RefCount=1]
str2 → [Data: "hello" | RefCount=1] // 新副本
  • 原数据引用计数减1。

  • str2创建独立副本并修改首字母。


3. 隐式共享的优势

场景无隐式共享隐式共享
传递参数深拷贝,内存+时间开销仅指针拷贝
容器存储相似字符串多份独立内存共享内存,节省空间
只读操作无优化零复制开销

尤其在函数参数传递上,隐式拷贝能尽量的减少性能浪费。

但为什么不用 const QString & 呢?


4. 关键代码验证

#include <QString>
#include <QDebug>void printAddress(const QString& s, const char* name) {qDebug() << name << " address:" << s.constData();
}int main() {QString s1 = "Shared Data";QString s2 = s1; // 浅拷贝printAddress(s1, "s1"); // 输出相同地址printAddress(s2, "s2");s2[0] = 'X'; // 触发COWprintAddress(s1, "s1"); // s1地址不变printAddress(s2, "s2"); // s2指向新地址return 0;
}

输出

s1 address: 0x55f1a5c4b2a0
s2 address: 0x55f1a5c4b2a0  // 修改前共享地址
s1 address: 0x55f1a5c4b2a0
s2 address: 0x55f1a5c4b7e0  // 修改后地址分离

5. 注意事项

5.1 多线程安全

  • 只读操作:线程安全(共享数据不可变)。

  • 写入操作:需加锁或使用QString::detach()强制分离:

    QString s2 = s1;
    s2.detach(); // 显式分离数据(即使未修改)

5.2 避免意外拷贝

以下操作会隐式触发深拷贝

// 通过非常量引用访问字符
QChar* data = s2.data(); // 调用data()即触发COW!// 使用迭代器修改
QString::iterator it = s2.begin();
*it = 'Y'; // 触发深拷贝

5.3 API选择

  • 优先使用 const QString& 传递参数。

  • 只读访问用 constData() 或 operator[] const


6. 隐式共享的底层实现

Qt通过 QSharedDataPointer 管理引用计数:

// 简化版QString内部结构
class QString {
private:struct Data {QAtomicInt ref;  // 原子引用计数int alloc, size; // 内存分配信息char* ptr;       // 实际数据};Data* d; // 指向共享数据块
};
  • ref 为原子变量,保证线程安全。

  • 析构时:if (--d->ref == 0) delete d;

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/diannao/93031.shtml
繁体地址,请注明出处:http://hk.pswp.cn/diannao/93031.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

命令行创建 UV 环境及本地化实战演示—— 基于《Python 多版本与开发环境治理架构设计》的最佳实践

命令行创建 UV 环境及本地化实战&#xff1a;基于架构设计的最佳实践 Python 多版本环境治理理念驱动的系统架构设计&#xff1a;三维治理、四级隔离、五项自治 原则-CSDN博客 使用 Conda 工具链创建 UV 本地虚拟环境全记录——基于《Python 多版本与开发环境治理架构设计》-CS…

跨域问题全解:从原理到实战

在计算机网络中&#xff0c;跨域&#xff08;Cross-Origin&#xff09; 指的是浏览器出于安全考虑&#xff0c;限制网页脚本&#xff08;如 JavaScript&#xff09;向与当前页面不同源&#xff08;Origin&#xff09; 的服务器发起请求的行为。这是由浏览器的同源策略&#xff…

(46)elasticsearch-华为云CCE无状态负载部署

一、准备好elasticsearch镜像并提前上传到镜像仓库 此次准备的是elasticsearch:v7.10.2 二、开始部署 负载名称:es-deployment 注意:内部配额太低会造成多次重启 环境变量: #单节点启动(实例pod可以多增加几个) discovery.type single-node 三、添加svc 四、注意:…

HCLP--MGER综合实验

一、拓扑图二、需求1、R5为ISP&#xff0c;只能进行IP地址配置&#xff0c;其所有地址均配为公有I地址; 2、R1和R5间使用PPP的PAP认证&#xff0c;R5为主认证方&#xff0c; R2与R5之间使用ppp的CHAP认证&#xff0c;R5为主认证方; R3与R5之间使用HDLc封装; 3、R1、R2、R3构建一…

idea中无法删除模块,只能remove?

1.先对module右键想要删除的module&#xff0c;选择remove module&#xff08;这是idea为了避免误操作&#xff09; 2.在remove module后&#xff0c;模块并未从项目结构中删除&#xff08;磁盘中也依旧存在&#xff09;&#xff0c;但再次右击你会发现&#xff0c;出现了del…

青藤天睿RASP再次发威!捕获E签宝RCE 0day漏洞

在2025年HVV关键攻防节点上&#xff0c;攻击队对E签宝电子合同服务发起的0day攻击被青藤天睿RASP截获。该漏洞可使攻击者在未授权情况下实现服务器远程代码执行&#xff08;RCE&#xff09;&#xff0c;进而控制服务器&#xff0c;构成横向渗透的关键跳板。>>>>漏洞…

Lua(字符串)

Lua字符串基础Lua中的字符串是不可变序列&#xff0c;可以包含任意字节数据&#xff08;包括嵌入的\0&#xff09;。字符串可以用单引号、双引号或长括号&#xff08;[[ ]]&#xff09;定义&#xff1a;str1 "Hello" str2 World str3 [[Multi-line string]]字符串…

大模型蒸馏(distillation)---从DeepseekR1-1.5B到Qwen-2.5-1.5B蒸馏

目录 1.1 蒸馏目标 2 环境准备 2.1依赖库安装 2.2 硬件要求 2.3 模型与数据集下载 2.3.1 教师模型下载 2.3.2 学生模型下载 2.3.3 数据集准备或下载 3.过程日志 4. 模型加载与配置 4.1 加载教师模型 4.2 加载学生模型 4.3 数据预处理函数 4.4 数据收集器 4.5 定义…

通过redis_exporter监控redis cluster

环境说明&#xff1a; 现在有一套redis cluster&#xff0c;部署是3主机6实例架构部署。需要采集对应的指标&#xff0c;满足异常监控告警&#xff0c;性能分析所需。 环境准备 以下环境需要提前部署完成。 redis cluser prometheus alertmanager grafna redis_exporter部署 我…

第二十天(正则表达式与功能实际运用)

在程序员一生的工作中&#xff0c;遇到的最多的数据就是字符串字符串里面很有可能有很多的不需要的信息我们需要从中间挑选出我们需要的如果循环去写&#xff0c;比较简单的时候问题不大规则多了&#xff0c;你的工作量会成倍上升的为了解决这个问题 ---- 正则表达式正则表达式…

0基础法考随手笔记 03(刑诉05 刑事证据与证明+06 强制措施)

1.如何区分书证和电子数据 书面材料是否为书证&#xff1f;→ 看内容是否直接源于案件事实&#xff08;不是 “记录别人陈述” 的载体&#xff09;。 证据清单是否为证据&#xff1f;→ 看谁做的清单&#xff08;侦查人员做的勘查笔录是证据&#xff0c;当事人做的目录不是&…

资产负债表及其数据获取

文章目录资产负债表及其数据获取资产负债表资产负债表在股票投资中的意义AKShare中的资产负债表数据接口&#xff08;深沪为例&#xff09;接口描述调用示例总结资产负债表及其数据获取 资产负债表 资产负债表&#xff08;Balance Sheet&#xff09;是反映企业在某一特定日期财…

数据仓库深度探索系列 | 开篇:开启数仓建设新征程

数据仓库深度探索系列 | 开篇&#xff1a;开启数仓建设新征程 在当今信息技术飞速发展的背景下&#xff0c;企业面临着数据量的爆炸式增长。企业不仅要高效管理海量数据&#xff0c;还需从中提取关键信息以支持复杂决策。数据仓库已从单纯的数据存储工具&#xff0c;演变为支持…

Linux如何执行系统调用及高效执行系统调用:深入浅出的解析

文章目录如何执行系统调用及高效执行系统调用&#xff1a;深入浅出的解析一、什么是系统调用&#xff1f;1.1 系统调用的作用1.2 系统调用的分类二、如何执行系统调用&#xff1f;2.1 系统调用的触发2.2 库函数与系统调用的关系2.3 系统调用的示例2.4 错误处理三、如何高效执行…

基于 XGBoost 与 SHAP 的医疗自动化办公与可视化系统(上)

摘要 随着信息技术的飞速发展和医疗健康数据的爆炸式增长,现代医疗机构面临着日益复杂的数据处理挑战。医生和行政人员常常需要花费大量时间在数据提取、整理、分析和报告生成等重复性、事务性的工作上,这不仅降低了工作效率,也限制了医护人员将更多精力投入到直接的患者护…

基于Kafka实现简单的延时队列

生命无罪&#xff0c;健康万岁&#xff0c;我是laity。 我曾七次鄙视自己的灵魂&#xff1a; 第一次&#xff0c;当它本可进取时&#xff0c;却故作谦卑&#xff1b; 第二次&#xff0c;当它在空虚时&#xff0c;用爱欲来填充&#xff1b; 第三次&#xff0c;在困难和容易之间&…

OceanBase 4.3.5 解析:DDL性能诊断

背景DDL操作通常耗时较长&#xff0c;特别是涉及补数据流程的DDL语句。在执行过程中&#xff0c;用户面临两个主要痛点&#xff1a;一是无法实时获取DDL执行进度&#xff0c;难以区分长时间运行是正常现象还是由内部异常导致的停滞&#xff1b;二是执行效率经常低于预期&#x…

幸福网咖订座点餐小程序的设计与实现

文章目录前言详细视频演示具体实现截图后端框架SpringBoot微信小程序持久层框架MyBaits成功系统案例&#xff1a;参考代码数据库源码获取前言 博主介绍:CSDN特邀作者、985高校计算机专业毕业、现任某互联网大厂高级全栈开发工程师、Gitee/掘金/华为云/阿里云/GitHub等平台持续…

C语言————练习题册(答案版)

目录 每日更新5-10题&#xff0c;感兴趣可以订阅 一.理解函数、操作符、占位符 1.1 欢迎来到C语言的世界 1.2 输入和输出 1.3 浮点数的打印 1.4 字符串的打印 1.14 I am iron man 1.5 求和运算 1.6 计算比例 1.7 求商求余 1.8 不同数位上的数字 1.8.1 求个位数 1.8…

haproxy配置详解

1、haproxy简介 HAProxy是法国开发者 威利塔罗(Willy Tarreau) 在2000年使用C语言开发的一个开源软件 是一款具备高并发(万级以上)、高性能的TCP和HTTP负载均衡器 支持基于cookie的持久性&#xff0c;自动故障切换&#xff0c;支持正则表达式及web状态统计 企业版网站&#xff…