Qt 隐式共享

隐性共享

Qt 中的许多 C++ 类都使用隐式数据共享,以最大限度地提高资源利用率并减少复制。隐式共享类在作为参数传递时既安全又高效,因为只传递指向数据的指针,只有在函数写入数据时才复制数据,即时复制。

概述

共享类由指向共享数据块的指针组成,共享数据块包含引用计数和数据

每当有新对象引用共享数据时,引用计数就会递增,而当对象取消引用共享数据时,引用计数就会递减。当引用计数变为 0 时,共享数据将被删除。

在处理共享对象时,有两种复制对象的方法。我们通常说的是拷贝和拷贝。深度拷贝意味着复制一个对象。浅层拷贝是引用拷贝,即只是指向共享数据块的指针。深度拷贝需要耗费大量内存和 CPU。浅层拷贝的速度非常快,因为它只需要设置一个指针并增加引用计数。

隐式共享对象的对象赋值(使用 operator=())就是通过浅层拷贝实现的。

共享的好处是,程序无需不必要地重复数据,从而减少了内存使用和数据复制。对象可以很容易地进行赋值、作为函数参数发送以及从函数中返回。

隐式共享大多发生在幕后,程序员很少需要担心。不过,Qt 的容器迭代器的行为与 STL 的容器迭代器不同。阅读隐式共享迭代器问题。

在多线程应用程序中,隐式共享会发生,详见《线程和隐式共享类》(Threads and Implicitly Shared Classes)。

在实现您自己的隐式共享类时,请使用QSharedData 和QSharedDataPointer 类。

线程和隐式共享类

        Qt 对其许多值类(尤其是QImage 和QString )使用了一种称为隐式共享的优化方法。从 Qt 4 开始,隐式共享类可以像其他值类一样安全地跨线程复制。它们是完全可重入的(不是线程安全)。隐式共享确实是隐式的

        在很多人的印象中,隐式共享和多线程是不相容的概念,因为引用计数通常是这样进行的。然而,Qt 使用原子引用计数来确保共享数据的完整性,避免了引用计数器的潜在损坏。

        请注意,原子引用计数并不能保证线程安全。在线程间共享隐式共享类的实例时,应使用适当的锁定。这是对所有重入类的相同要求,无论是否共享。不过,原子引用计数确实能保证在隐式共享类的本地实例上工作的线程是安全的(意思是不同对象在不同线程里是安全,同一对象在多线程不是安全的)。我们建议使用信号和槽在线程间传递数据,因为这样做无需任何显式锁定。

        总而言之,Qt 4 中的隐式共享类确实是隐式共享。即使在多线程应用程序中,您也可以像使用普通的、非共享的、基于值的可重入类一样安全地使用它们。

隐式共享的工作原理

  1. 共享数据块
    多个对象内部指向同一份数据块,数据块包含 数据内容 和 引用计数器

  2. 引用计数
    当新对象通过拷贝构造函数或赋值操作符创建时,引用计数加 1,不实际复制数据。

  3. 写时复制(COW)
    当某个对象尝试修改数据时,检查引用计数:

    • 若引用计数为 1(唯一所有者),直接修改数据。

    • 若引用计数大于 1(共享数据),创建数据的独立副本,修改副本,并将引用计数减 1。

隐式共享详解

如果对象即将发生变化且引用计数大于 1,隐式共享会自动将对象从共享块中分离。(这通常称为写时复制 或值语义)。

隐式共享类可控制其内部数据。在任何修改其数据的成员函数中,它都会在修改数据前自动脱离。不过,请注意容器迭代器的特殊情况;请参阅隐式共享迭代器问题。

使用隐式共享的QPen 类在所有修改内部数据的成员函数中都会脱离共享数据。

代码片段:

void QPen::setStyle(Qt::PenStyle style)
{detach();           // detach from common datad->style = style;   // set the style member
}void QPen::detach()
{if (d->ref != 1) {...             // perform a deep copy}
}

类列表

如果要更改对象,下面列出的类会自动从公共数据中分离出来。程序员甚至不会注意到这些对象是共享的。因此,应将它们的独立实例视为独立对象。它们的行为始终与独立对象无异,但却具有尽可能共享数据的额外好处。因此,您可以将这些类的实例作为参数按值传递给函数,而不必担心复制开销。

示例

QPixmap p1, p2;
p1.load("image.bmp");
p2 = p1;                        // p1 and p2 share dataQPainter paint;
paint.begin(&p2);               // cuts p2 loose from p1
paint.drawText(0,50, "Hi");
paint.end();

在本例中,p1 和p2 共享数据,直到QPainter::begin() 被调用为p2 ,因为绘制像素图会修改数据。

Implicit Sharing | Qt Core 6.8.2

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

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

相关文章

深度学习PyTorch之动态计算图可视化 - 使用 torchviz 生成计算图

序号系列文章1深度学习训练中GPU内存管理2深度学习PyTorch之数据加载DataLoader3深度学习 PyTorch 中 18 种数据增强策略与实现4深度学习pytorch之简单方法自定义9类卷积即插即用5深度学习PyTorch之13种模型精度评估公式及调用方法6深度学习pytorch之4种归一化方法(…

ZW3D二次开发_非模板表单_输入框类控件_逐字符回调

ZW3D的非模板表单的控件中有一些输入框类的控件,比如“ZsCc::LineEditBtn”,"ZsCc::LineEditEx"等,按照“ZW3D二次开发_非模板表单_控件_添加回调-CSDN博客”介绍的方法添加函数命令时,发现输入框在用户输入字符时不能动态地触发回…

Mysql--日志(错误日志、二进制日志、查询日志、慢查询日志)

四种日志对比总结 日志类型作用记录内容特点常见用途错误日志记录 MySQL 运行过程中的错误、警告及启动、关闭信息MySQL 系统错误、故障信息、警告等较少占用磁盘空间故障排查、系统监控二进制日志记录所有更改数据库数据的操作及事务执行情况DML、DDL 操作,不记录…

AI对软件工程(software engineering)的影响在哪些方面?

AI对软件工程(software engineering)的影响是全方位且深远的,它不仅改变了传统开发流程,还重新定义了工程师的角色和软件系统的构建方式。以下是AI影响软件工程的核心维度: 一、开发流程的智能化重构 需求工程革命 • …

ElementPlus 快速入门

目录 前言 为什么要学习 ElementPlus? 正文 步骤 1 创建 一个工程化的vue 项目 ​2 安装 element-Plus :Form 表单 | Element Plus 1 点击 当前界面的指南 2 点击左边菜单栏上的安装,选择包管理器 3 运行该命令 demo(案例1 ) 步骤 …

stable diffusion本地安装

1. 基本环境准备 安装conda 环境 pytorch基础学习-CSDN博客 创建虚拟环境: conda create -n sd python3.10 一定要指定用3.10,过高的版本会提示错误: 激活启用环境: conda activate sd 设置pip国内镜像源: pip conf…

使用 Go 构建 MCP Server

一个互联网技术玩家,一个爱聊技术的家伙。在工作和学习中不断思考,把这些思考总结出来,并分享,和大家一起交流进步。 一、MCP 介绍 1. 基本介绍 MCP(Model Context Protocol,模型上下文协议)是…

Python----计算机视觉处理(Opencv:模板匹配)

一、 概念 模板匹配就是用模板图(通常是一个小图)在目标图像(通常是一个比模板图大的图片)中不断的滑动 比较,通过某种比较方法来判断是否匹配成功。 二、应用场景 1. 目标检测与识别:在计算机视觉领域&am…

【stm32】用从模式控制器 完成PWM的测量

🌞学习视频还是来自于 铁头山羊 🌿主要是回顾一下他讲的这一章的定时器的部分,具体的话 还是看一下具体铁头山羊的视频,讲的很清楚~~ 整体流程是这样的,首先通过定时器的输出比较功能,配置好PA6产生一个特定…

【C#】CS学习之Modbus通讯

摘要 本文详细描述了如何在在C#的Winform应用程序中使用NModbus库实现Modbus通讯,包括读取保持寄存器、以及相应的UI界面设计和事件处理。 前言 ​应用场景 Modbus 从站广泛应用于工业自动化领域: 1、传感器数据采集(如温度、压力等&#xf…

Pycharm社区版创建Flask项目详解

一、创建工程项目 二、配置工程目录 新建的空项目下创建目录。 1、新建app.py文件 2、app.py代码如下: from flask import Flask, render_templateapp Flask(__name__)app.route("/") def root():"""主页:return: Index.html"&qu…

Linux 基础入门操作 第十二章 TINY Web 服务器

1 服务器基础架构 1.1 背景知识 Web 服务器使用 HTTP 协议与客户端(即浏览器)通信,而 HTTP 协议又基于 TCP/IP 协议。因此我们要做的工作就是利用 Linux 系统提供的 TCP 通信接口来实现 HTTP 协议。 而 Linux 为我们提供了哪些网络编程接口…

RAG优化:python从零实现[吃一堑长一智]循环反馈Feedback

本文将介绍一种有反馈循环机制的RAG系统,让当AI学会"吃一堑长一智",给传统RAG装了个"后悔"系统,让AI能记住哪些回答被用户点赞/拍砖,从此告别金鱼记忆: 每次回答都像在玩roguelike:失败结局会强化下次冒险悄悄把优质问答变成新知识卡牌,实现"以…

基于SpringBoot的名著阅读网站

作者:计算机学姐 开发技术:SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等,“文末源码”。 专栏推荐:前后端分离项目源码、SpringBoot项目源码、Vue项目源码、SSM项目源码、微信小程序源码 精品专栏:…

[AI建模] 使用Pinokio本地化部署混元2D到3D AI建模服务

近年来,AI驱动的2D转3D建模技术发展迅猛,而Pinokio作为一个强大的AI模型管理与部署平台,使得在本地部署这些复杂的AI模型变得更加简单高效。本文将介绍如何使用Pinokio在本地部署混元2D到3D AI建模服务,并快速生成带或不带Texture的3D模型。 1. 在Pinokio Discover页面找到…

Qt 导入TagLib库

文章目录 0. 前言和环境介绍1. 下载TagLib2. 下载zlib3. 修改.pro文件4. 测试代码 0. 前言和环境介绍 最近在使用Qt写一个播放器,需要解析mp3文件,于是研究了一下如何导入TagLib库 Qt构建套件:Desktop Qt6.8.2 MinGW64-bit Qt Creator安装目录: D:\bit…

【前端面试题】计算机网络相关

总结面试前端过程可能会问到的计算机网络相关知识点 1.HTTP和HTTPS的区别 (1)HTTPS HTTP 安全加密 HTTPS 是 HTTP 的 加密版,通过 SSL/TLS 保障数据安全,防止窃听和篡改。 (2)HTTPS 如何保护数据&…

【RabbitMQ高级特性】消息确认机制、持久化、发送方确认、TTL和死信队列

🔥个人主页: 中草药 🔥专栏:【中间件】企业级中间件剖析 一、消息确认机制 消费者确认机制确保消息被正确处理后才从队列中删除。如果消费者处理失败(如业务异常或宕机),Broker 会重新投递消息…

调用百度api实现语音识别(python)

该代码实现了一个企业级的语音识别解决方案,通过调用百度语音识别API,实现实时录音识别和对已有音频语音识别功能。 百度智能云:请自行访问百度智能云,开通免费的语音识别功能,获取API_KEY和SECRET_KEY。操作按照百度流程即可,可免费申请。 首先,配置下百度API和描述下错…

Python实现小红书app版爬虫

简介:由于数据需求的日益增大,小红书网页版已经不能满足我们日常工作的需求,为此,小编特地开发了小红书手机版算法,方便大家获取更多的数据,提升工作效率。 手机版接口主要包括:搜素&#xff0…