QT(18):QString
目录
- QString
- QTypedArrayData
- QTypedArrayData
- QLatin1String
- QStringLiteral
- 乱码
- QStringRef
QString
QString 存储16位QChar的字符串,其中每个QChar对应一个 UTF-16代码单元。QString 使用(写入时复制copy-on-write)来减少内存使用并避免不必要的数据复制。这也有助于减少存储16位字符而不是8位字符的固有开销。
除了QString之外,Qt还提供了存储原始字节和传统8位“\0”结尾字符串的QByteArray类。在大多数情况下,使用QString,Unicode支持使得应用程序将很容易翻译。使用QByteArray类时合适的两种主要情况是需要存储原始二进制数据时,以及内存保护至关重要时(如在嵌入式系统中)。
typedef QStringData Data;
typedef QTypedArrayData<ushort> QStringData;
class Q_CORE_EXPORT QString
{
public:typedef QStringData Data;//构造函数、拷贝函数、赋值运算符...........//字符串属性函数、字符串操作函数,修改、比较、查找..........
private:Data *d;
};
QString内部除了定义的函数之外,成员变量只有Data类型的指针,指向字符数据地址。内部采用共享机制,在QString对象赋值时只是类似智能指针执行浅拷贝,简单复制指针d的值,增加引用计数。同时QString采用写时复制机制,只在修改数据时执行深拷贝,复制字符数据并进行写操作。
QString在构造时调用QTypedArray的allocate函数,将返回的地址赋值给指针d。以QChar为参数的构造函数,size设置为1,data返回地址开始存储字符数据,末尾存储结束字符。
QString::QString(QChar ch)
{d = Data::allocate(2);Q_CHECK_PTR(d);d->size = 1;d->data()[0] = ch.unicode();d->data()[1] = '\0';
}
以QString的const &为参数的拷贝构造函数只是复制指针,ref()增加计数值。
inline QString::QString(const QString &other) noexcept : d(other.d)
{ Q_ASSERT(&other != this); d->ref.ref(); }
析构函数中,当引用计数为零时才会调用deallocate函数释放内存。
inline QString::~QString() { if (!d->ref.deref()) Data::deallocate(d); }
在使用left()、mid()等字符串操作时会修改字符串,此时会创建新的QString对象并在构造函数使用memcpy()进行深拷贝。
QString QString::left(int n) const
{if (uint(n) >= uint(d->size))return *this;return QString((const QChar*) d->data(), n);
}
QTypedArrayData
QString的数据存放在指针d指向的对象中,对象类型为QTypedArrayData,继承自QArrayData。
QTypedArrayData重写的data()、allocate()、reallocateUnaligned()、deallocate()、sharedNull()都是直接调用了父结构体的函数,此外还基于data()封装了一些迭代器操作。
在QString中,类模板QTypedArrayData的模板实参T为ushort,所以是以两字节的方式存储字符数据的。data函数的返回值为ushort类型的指针,后续在QString中通过data()返回指针的[]运算符函数对字符数据进行操作。
template <class T>
struct QTypedArrayData: QArrayData
{typedef T* iterator;typedef const T* const_iterator;T *data() { return static_cast<T *>(QArrayData::data()); }const T *data() const { return static_cast<const T *>(QArrayData::data()); }iterator begin(iterator = iterator()) { return data(); }iterator end(iterator = iterator()) { return data() + size; }const_iterator begin(const_iterator = const_iterator()) const { return data(); }const_iterator end(const_iterator = const_iterator()) const { return data() + size; }const_iterator constBegin(const_iterator = const_iterator()) const { return data(); }const_iterator constEnd(const_iterator = const_iterator()) const { return data() + size; }class AlignmentDummy { QArrayData header; T data; };Q_REQUIRED_RESULT static QTypedArrayData *allocate(size_t capacity,AllocationOptions options = Default){Q_STATIC_ASSERT(sizeof(QTypedArrayData) == sizeof(QArrayData));return static_cast<QTypedArrayData *>(QArrayData::allocate(sizeof(T),Q_ALIGNOF(AlignmentDummy), capacity, options));}static QTypedArrayData *reallocateUnaligned(QTypedArrayData *data, size_t capacity,AllocationOptions options = Default){Q_STATIC_ASSERT(sizeof(QTypedArrayData) == sizeof(QArrayData));return static_cast<QTypedArrayData *>(QArrayData::reallocateUnaligned(data, sizeof(T),capacity, options));}static void deallocate(QArrayData *data){Q_STATIC_ASSERT(sizeof(QTypedArrayData) == sizeof(QArrayData));QArrayData::deallocate(data, sizeof(T), Q_ALIGNOF(AlignmentDummy));}static QTypedArrayData *fromRawData(const T *data, size_t n,AllocationOptions options = Default) { //.............}static QTypedArrayData *sharedNull() noexcept{Q_STATIC_ASSERT(sizeof(QTypedArrayData) == sizeof(QArrayData));return static_cast<QTypedArrayData *>(QArrayData::sharedNull());}static QTypedArrayData *sharedEmpty(){Q_STATIC_ASSERT(sizeof(QTypedArrayData) == sizeof(QArrayData));return allocate(/* capacity */ 0);}#if !defined(QT_NO_UNSHARABLE_CONTAINERS)static QTypedArrayData *unsharableEmpty(){Q_STATIC_ASSERT(sizeof(QTypedArrayData) == sizeof(QArrayData));return allocate(/* capacity */ 0, Unsharable);}
#endif
};
QTypedArrayData
QTypedArrayData重写的data()、allocate()、reallocateUnaligned()、deallocate()、sharedNull()都是直接调用了父结构体QArrayData的函数,所以字符数据和基础的操作都定义在QArrayData中,QArrayData即数据容器。
[ref|size|alloc|reserve|offset|--the real data--]
struct Q_CORE_EXPORT QArrayData
{QtPrivate::RefCount ref;int size;uint alloc : 31;uint capacityReserved : 1;qptrdiff offset; //从标头开头开始的字节数void *data(){Q_ASSERT(size == 0 || offset < 0 || size_t(offset) >= sizeof(QArrayData));return reinterpret_cast<char *>(this) + offset;}const void *data() const {//.......}//这是指数组数据的可变性,而不是 QArrayData 中数据成员表示的“标头数据”。//共享数据(数组和标头)仍必须遵循 COW 原则。bool isMutable() const { return alloc != 0; }enum AllocationOption {//内存分配方式CapacityReserved = 0x1,//调整内存大小或克隆时至少保留原始容量大小。
#if !defined(QT_NO_UNSHARABLE_CONTAINERS)Unsharable = 0x2,//非共享的,在克隆时必须重新分配内存
#endifRawData = 0x4,//如果设置了RawData,分配内存时就会忽略填充而使数据紧贴在QArrayData头之后。Grow = 0x8,//会分配超出用户要求的内存,达到比用户要求数量更大的下一个2次幂Default = 0//};Q_DECLARE_FLAGS(AllocationOptions, AllocationOption)size_t detachCapacity(size_t newSize) const {//................}AllocationOptions detachFlags() const {//................}AllocationOptions cloneFlags() const {//................}Q_REQUIRED_RESULT static QArrayData *allocate(size_t objectSize, size_t alignment,size_t capacity, AllocationOptions options = Default) noexcept;Q_REQUIRED_RESULT static QArrayData *reallocateUnaligned(QArrayData *data, size_t objectSize,size_t newCapacity, AllocationOptions newOptions = Default) noexcept;static void deallocate(QArrayData *data, size_t objectSize,size_t alignment) noexcept;static const QArrayData shared_null[2];static QArrayData *sharedNull() noexcept { return const_cast<QArrayData*>(shared_null); }
};
通过QChar或者char实例化一个QString对象时调用allocate函数,内部调用了malloc分配内存,并将QArrayData指针对象header指向该内存,初始化标头数据,并返回header赋值给指针d。
QArrayData *QArrayData::allocate(size_t objectSize, size_t alignment,size_t capacity, AllocationOptions options) noexcept
{//..............QArrayData *header = static_cast<QArrayData *>(::malloc(allocSize));if (header) {quintptr data = (quintptr(header) + sizeof(QArrayData) + alignment - 1)& ~(alignment - 1);#if !defined(QT_NO_UNSHARABLE_CONTAINERS)header->ref.atomic.storeRelaxed(bool(!(options & Unsharable)));
#elseheader->ref.atomic.storeRelaxed(1);
#endifheader->size = 0;header->alloc = capacity;header->capacityReserved = bool(options & CapacityReserved);header->offset = data - quintptr(header);}return header;
}
QLatin1String
如果没有定义QT_NO_CAST_FROM_ASCII和QT_RESTRICTED_CAST_FROM_ASCII两个宏,在QString中会定义一系列以const char*为参数的函数,比如拷贝构造函数和拷贝赋值运算符,支持QString和字符串常量的转换和比较。而如果定义了该宏,类似 QString dd = "example"和dd == "example" 的操作是不能通过编译的,因为相关函数将失效,并且定义QT_NO_CAST_FROM_ASCII后将几个函数定义成私有的。
Qt提供了QLatin1String类来更高效的利用const char*的类型,dd == "example"转换成dd == QLatin1String("example")
虽然在代码输入的时候有点长,但是两者效率差不多,同时也比使用QString::fromLatin1()转换更快。
class QLatin1String
{
public:Q_DECL_CONSTEXPR inline QLatin1String() noexcept : m_size(0), m_data(nullptr) {}Q_DECL_CONSTEXPR inline explicit QLatin1String(const char *s) noexcept : m_size(s ? int(strlen(s)) : 0), m_data(s) {}Q_DECL_CONSTEXPR explicit QLatin1String(const char *f, const char *l): QLatin1String(f, int(l - f)) {}Q_DECL_CONSTEXPR inline explicit QLatin1String(const char *s, int sz) noexcept : m_size(sz), m_data(s) {}inline explicit QLatin1String(const QByteArray &s) noexcept : m_size(int(qstrnlen(s.constData(), s.size()))), m_data(s.constData()) {}Q_DECL_CONSTEXPR const char *latin1() const noexcept { return m_data; }Q_DECL_CONSTEXPR int size() const noexcept { return m_size; }Q_DECL_CONSTEXPR const char *data() const noexcept { return m_data; }//字符串操作//类型别名
private:int m_size;const char *m_data;
};
QStringLiteral
在编译时构造QString对象,适用于只能接受QString参数的场景,转换后的字符串数据存储在编译后文件的只读数据段中,使用时读取。接受const char *或QLatin1String直接使用比该宏更高效。
乱码
const char *字符默认UTF-8编码,QString采用UTF-16编码。根据源文件相应格式解码后,Windows环境下可执行文件中的字符串是本地编码格式GBK编码,运行时以UTF-8解码,再进行UTF-16编码就会出现乱码。
解决方法:
1、解码:QStringLiteral()宏或者QString::fromLocal8Bit()封装字符串
2、编码:编译器采用UTF-8编码生成可执行文件
#if _MSC_VER >= 1600
#pragma execution_character_set("utf-8")
#endif
QStringRef
QStringRef 提供 API 的只读子集。此类旨在提高操作从现有实例获取的子字符串时子字符串处理的性能。QStringRef 通过简单地引用原始字符串的一部分来避免标准的内存分配和引用计数开销(修改字符串操作如mid、left、right等,会创建一个新的字符串,申请空间并拷贝数据)。这在低级代码(例如解析器中使用的代码)中可能被证明是有利的,但代价是可能更复杂的代码。
对于大多数用户来说,使用 QStringRef 而不是 QStringRef 没有语义上的好处,因为 QStringRef 需要注意内存管理问题,这可能会使代码的编写和维护更加复杂。
class Q_CORE_EXPORT QStringRef {const QString *m_string;int m_position;int m_size;
public:inline QStringRef(const QString *string, int position, int size);//............
};
相关文章:
QT(18):QString
目录 QStringQTypedArrayDataQTypedArrayDataQLatin1StringQStringLiteral乱码 QStringRef QString QString 存储16位QChar的字符串,其中每个QChar对应一个 UTF-16代码单元。QString 使用(写入时复制copy-on-write)来减少内存使用并避免不必…...
宏工科技通过CMMI三级认证,软件研发能力获国际权威认可
近日,宏工科技子公司湖南宏工软件成功通过CMMI三级认证并正式获得资质证书,斩获全球软件领域最权威的认证之一,标志着宏工科技在软件技术开发、研发管理、项目管理等多方面获得国际权威认证。 CMMI全称是Capability Maturity Model Integrati…...
2次MD5加密——用于分布式对话
用户端 : 指发起请求并与服务器进行交互的终端设备或应用程序。它可以是电脑、智能手机等。 用户端负责发送请求给服务端,并接收和处理服务端返回的响应。 服务端 : 是指提供服务、接收和处理用户端请求的计算机系统或应用程序。 它监听来自用…...
用Java制作简易版的王者荣耀
第一步是创建项目 项目名自拟 第二部创建个包名 来规范class 创建类 GameFrame 运行类 package com.sxt;import java.awt.Graphics; import java.awt.Image; import java.awt.Toolkit; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import j…...
android 保活的一种有效的方法
android 保活的一种有效的方法 为什么要保活 说起程序的保活,其实很多人都觉得,要在手机上进行保活,确实是想做一些小动作,其实有些正常的场景也是需要我们进行保活的,这样可以增强我们的用户体验。保活就是使得程序…...
kibana安装
kibana安装下载注意事项 地址:curl -O https://artifacts.elastic.co/downloads/kibana/kibana-7.16.3-linux-x86_64.tar.gz 下载后直接解压启动即可 1. 但需要使用非root用户启动 ,root用户启动会报错 2. kibana需要和elasticsearch版本一致 不然…...
LV.12 D19 ADC实验 学习笔记
一、ADC简介 1.1 ADC ADC(Analog to Digital Converter)即模数转换器,指一个能将模拟信号转化为数字信号的电子元件 1.2 ADC主要参数 分辨率 ADC的分辨率一般以输出二进制数的位数来表示,当最大输入电压一定时,位数越高,…...
ubuntu配置免密登录vscode
1、配置免密登录 (1)在windows系统cmd下运行命令 ssh-keygen 一路回车,将会在C:\Users\用户名\.ssh目录下生成两个文件:id_rsa和id_rsa.pub。如下图所示。 (2)进入.ssh目录。如果想使用root用户࿰…...
软件工程--面向对象分析用通俗语言20小时爆肝总结!(包含用例图、活动图、类图、时序图......)
面向对象方法分为面向对象分析(OOA)、面向对象设计(OOD)、面向对象编程(OOP),本文详细介绍面向对象分析 本文参考教材:沈备军老师的《软件工程原理》大多图片来源其中 目录 面向对…...
HarmonyOS—ArkTS中@Observed和@ObjectLink装饰器的嵌套类对象属性变化【鸿蒙专栏-11】
文章目录 ARKTS中@Observed和@ObjectLink装饰器的嵌套类对象属性变化@Observed 类装饰器说明装饰器参数类装饰器的使用@ObjectLink 变量装饰器说明装饰器参数同步类型允许装饰的变量类型被装饰变量的初始值举例装饰器的限制条件观察变化和行为表现观察的变化框架行为使用场景1.…...
网络通信安全的坚固防线双向认证技术详解
目录 什么是双向认证 双向认证的工作原理 双向认证的实现方式 双向认证的重要性 双向认证的挑战 安全最佳实践 小结 什么是双向认证 双向认证,又称为双向身份验证或双向鉴别,是一种在通信双方之间建立信任关系的安全机制。在通信过程中࿰…...
Appium+python+unittest搭建UI自动化框架
阅读本小节,需要读者具备如下前提条件: 1. 掌握一种编程语言基础,如java、python等。 2. 掌握一种单元测试框架,如java语言的testng框架、python的unittest框架。 3. 掌握目前主流的UI测试框架,移动端APP测试框架…...
使用paddledetection的记录
首先在这里使用的是是paddle--detection2.7的版本。 成功进行训练 目录: 目录 数据集准备 配置文件的修改 使用的是BML的平台工具: !python -m pip install paddlepaddle-gpu2.5 -i https://mirror.baidu.com/pypi/simple --user %cd /home/aistudio…...
MySQL数据库的备份与恢复
在管理MySQL数据库时,备份和恢复是保证数据安全和完整性的关键环节。本文将指导您如何有效地备份MySQL数据库,并在需要时进行数据恢复。 请注意,如果没有 mysql> 的标志,说明我们是在外面终端进行的操作 创建备份文件路径 在…...
Pycharm配置jupyter使用notebook详细指南(可换行conda环节)
本教程为事后记录,部分图片非实操图片。 详细记录了pycharm配置jupyter的方法,jupyter添加其他conda环境的方法,远程密码调用jupyter的方法,修改jupyter工作目录的方法。 文章目录 一、入门级配置1. Pycharm配置Conda自带的jupyt…...
企业微信ipad版,http协议接口发开,获取客户群列表
版本介绍: HTTP协议接口可以通过该接口实现企业微信的各种功能,使用HTTP协议可以避免使用hook形式的需要开启PC客户端的方式,同时可以实现三端同时在线,不影响PC和手机端的登录状态,调用简单,可以支持几千…...
Double 4 VR智能互动教学系统在小语种课堂中的教学应用
小语种课堂一直是教育领域的一个难点。由于语言本身的复杂性和文化背景的差异,小语种教学一直是一个挑战。传统的课堂教学方法往往难以激发学生的学习兴趣和动力,教学效果不尽如人意。而Double 4 VR智能互动教学系统为小语种课堂带来了新的可能。 Double…...
OSEK OS任务调度的底层逻辑
先参考 FreeRTOS的任务触发底层逻辑 简述RTOS任务调度底层逻辑 AUTOSAR-OS的调度机制-调度表(没理解透,继续更新) OSEK与FreeRTOS在任务调度上最大的区别在于,FreeRTOS是基于全抢占任务调度和时间片轮转调度机制,具有…...
‘tsc‘ 不是内部或外部命令,也不是可运行的程序 或批处理文件。
最近在用nodejs typescript 某游戏服务器在做一些研究 nodejs-tcs 问题描述: 1.使用命令npm install -g typescript安装typescript后,输入 tsc命令,一直报错 tsc 不是内部或外部命令,也不是可运行的程序 或批处理文件。 2.目…...
windows文件删除权限
一、普通文件 这里指的是所有可以被随意删除的文件。 二、可更改权限的文件 如果想要删除的文件无法被删除,那大概是权限不够,这时候:鼠标右键、属性、安全、编辑、选择相应的组或用户(如果不知道哪个可以全选,反正…...
C++实现分布式网络通信框架RPC(3)--rpc调用端
目录 一、前言 二、UserServiceRpc_Stub 三、 CallMethod方法的重写 头文件 实现 四、rpc调用端的调用 实现 五、 google::protobuf::RpcController *controller 头文件 实现 六、总结 一、前言 在前边的文章中,我们已经大致实现了rpc服务端的各项功能代…...
智慧医疗能源事业线深度画像分析(上)
引言 医疗行业作为现代社会的关键基础设施,其能源消耗与环境影响正日益受到关注。随着全球"双碳"目标的推进和可持续发展理念的深入,智慧医疗能源事业线应运而生,致力于通过创新技术与管理方案,重构医疗领域的能源使用模式。这一事业线融合了能源管理、可持续发…...
2.Vue编写一个app
1.src中重要的组成 1.1main.ts // 引入createApp用于创建应用 import { createApp } from "vue"; // 引用App根组件 import App from ./App.vue;createApp(App).mount(#app)1.2 App.vue 其中要写三种标签 <template> <!--html--> </template>…...
Nuxt.js 中的路由配置详解
Nuxt.js 通过其内置的路由系统简化了应用的路由配置,使得开发者可以轻松地管理页面导航和 URL 结构。路由配置主要涉及页面组件的组织、动态路由的设置以及路由元信息的配置。 自动路由生成 Nuxt.js 会根据 pages 目录下的文件结构自动生成路由配置。每个文件都会对…...
如何为服务器生成TLS证书
TLS(Transport Layer Security)证书是确保网络通信安全的重要手段,它通过加密技术保护传输的数据不被窃听和篡改。在服务器上配置TLS证书,可以使用户通过HTTPS协议安全地访问您的网站。本文将详细介绍如何在服务器上生成一个TLS证…...
python如何将word的doc另存为docx
将 DOCX 文件另存为 DOCX 格式(Python 实现) 在 Python 中,你可以使用 python-docx 库来操作 Word 文档。不过需要注意的是,.doc 是旧的 Word 格式,而 .docx 是新的基于 XML 的格式。python-docx 只能处理 .docx 格式…...
IoT/HCIP实验-3/LiteOS操作系统内核实验(任务、内存、信号量、CMSIS..)
文章目录 概述HelloWorld 工程C/C配置编译器主配置Makefile脚本烧录器主配置运行结果程序调用栈 任务管理实验实验结果osal 系统适配层osal_task_create 其他实验实验源码内存管理实验互斥锁实验信号量实验 CMISIS接口实验还是得JlINKCMSIS 简介LiteOS->CMSIS任务间消息交互…...
大语言模型(LLM)中的KV缓存压缩与动态稀疏注意力机制设计
随着大语言模型(LLM)参数规模的增长,推理阶段的内存占用和计算复杂度成为核心挑战。传统注意力机制的计算复杂度随序列长度呈二次方增长,而KV缓存的内存消耗可能高达数十GB(例如Llama2-7B处理100K token时需50GB内存&a…...
OPENCV形态学基础之二腐蚀
一.腐蚀的原理 (图1) 数学表达式:dst(x,y) erode(src(x,y)) min(x,y)src(xx,yy) 腐蚀也是图像形态学的基本功能之一,腐蚀跟膨胀属于反向操作,膨胀是把图像图像变大,而腐蚀就是把图像变小。腐蚀后的图像变小变暗淡。 腐蚀…...
Linux离线(zip方式)安装docker
目录 基础信息操作系统信息docker信息 安装实例安装步骤示例 遇到的问题问题1:修改默认工作路径启动失败问题2 找不到对应组 基础信息 操作系统信息 OS版本:CentOS 7 64位 内核版本:3.10.0 相关命令: uname -rcat /etc/os-rele…...
