当前位置: 首页 > news >正文

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_ASCIIQT_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的字符串&#xff0c;其中每个QChar对应一个 UTF-16代码单元。QString 使用&#xff08;写入时复制copy-on-write&#xff09;来减少内存使用并避免不必…...

宏工科技通过CMMI三级认证,软件研发能力获国际权威认可

近日&#xff0c;宏工科技子公司湖南宏工软件成功通过CMMI三级认证并正式获得资质证书&#xff0c;斩获全球软件领域最权威的认证之一&#xff0c;标志着宏工科技在软件技术开发、研发管理、项目管理等多方面获得国际权威认证。 CMMI全称是Capability Maturity Model Integrati…...

2次MD5加密——用于分布式对话

用户端 &#xff1a; 指发起请求并与服务器进行交互的终端设备或应用程序。它可以是电脑、智能手机等。 用户端负责发送请求给服务端&#xff0c;并接收和处理服务端返回的响应。 服务端 &#xff1a; 是指提供服务、接收和处理用户端请求的计算机系统或应用程序。 它监听来自用…...

用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 保活的一种有效的方法 为什么要保活 说起程序的保活&#xff0c;其实很多人都觉得&#xff0c;要在手机上进行保活&#xff0c;确实是想做一些小动作&#xff0c;其实有些正常的场景也是需要我们进行保活的&#xff0c;这样可以增强我们的用户体验。保活就是使得程序…...

kibana安装

kibana安装下载注意事项 地址&#xff1a;curl -O https://artifacts.elastic.co/downloads/kibana/kibana-7.16.3-linux-x86_64.tar.gz 下载后直接解压启动即可 1. 但需要使用非root用户启动 &#xff0c;root用户启动会报错 2. kibana需要和elasticsearch版本一致 不然…...

LV.12 D19 ADC实验 学习笔记

一、ADC简介 1.1 ADC ADC(Analog to Digital Converter)即模数转换器&#xff0c;指一个能将模拟信号转化为数字信号的电子元件 1.2 ADC主要参数 分辨率 ADC的分辨率一般以输出二进制数的位数来表示&#xff0c;当最大输入电压一定时&#xff0c;位数越高&#xff0c…...

ubuntu配置免密登录vscode

1、配置免密登录 &#xff08;1&#xff09;在windows系统cmd下运行命令 ssh-keygen 一路回车&#xff0c;将会在C:\Users\用户名\.ssh目录下生成两个文件&#xff1a;id_rsa和id_rsa.pub。如下图所示。 &#xff08;2&#xff09;进入.ssh目录。如果想使用root用户&#xff0…...

软件工程--面向对象分析用通俗语言20小时爆肝总结!(包含用例图、活动图、类图、时序图......)

面向对象方法分为面向对象分析&#xff08;OOA&#xff09;、面向对象设计&#xff08;OOD&#xff09;、面向对象编程&#xff08;OOP&#xff09;&#xff0c;本文详细介绍面向对象分析 本文参考教材&#xff1a;沈备军老师的《软件工程原理》大多图片来源其中 目录 面向对…...

HarmonyOS—ArkTS中@Observed和@ObjectLink装饰器的嵌套类对象属性变化【鸿蒙专栏-11】

文章目录 ARKTS中@Observed和@ObjectLink装饰器的嵌套类对象属性变化@Observed 类装饰器说明装饰器参数类装饰器的使用@ObjectLink 变量装饰器说明装饰器参数同步类型允许装饰的变量类型被装饰变量的初始值举例装饰器的限制条件观察变化和行为表现观察的变化框架行为使用场景1.…...

网络通信安全的坚固防线双向认证技术详解

目录 什么是双向认证 双向认证的工作原理 双向认证的实现方式 双向认证的重要性 双向认证的挑战 安全最佳实践 小结 什么是双向认证 双向认证&#xff0c;又称为双向身份验证或双向鉴别&#xff0c;是一种在通信双方之间建立信任关系的安全机制。在通信过程中&#xff0…...

Appium+python+unittest搭建UI自动化框架

阅读本小节&#xff0c;需要读者具备如下前提条件&#xff1a; 1. 掌握一种编程语言基础&#xff0c;如java、python等。 2. 掌握一种单元测试框架&#xff0c;如java语言的testng框架、python的unittest框架。 3. 掌握目前主流的UI测试框架&#xff0c;移动端APP测试框架…...

使用paddledetection的记录

首先在这里使用的是是paddle--detection2.7的版本。 成功进行训练 目录&#xff1a; 目录 数据集准备 配置文件的修改 使用的是BML的平台工具&#xff1a; !python -m pip install paddlepaddle-gpu2.5 -i https://mirror.baidu.com/pypi/simple --user %cd /home/aistudio…...

MySQL数据库的备份与恢复

在管理MySQL数据库时&#xff0c;备份和恢复是保证数据安全和完整性的关键环节。本文将指导您如何有效地备份MySQL数据库&#xff0c;并在需要时进行数据恢复。 请注意&#xff0c;如果没有 mysql> 的标志&#xff0c;说明我们是在外面终端进行的操作 创建备份文件路径 在…...

Pycharm配置jupyter使用notebook详细指南(可换行conda环节)

本教程为事后记录&#xff0c;部分图片非实操图片。 详细记录了pycharm配置jupyter的方法&#xff0c;jupyter添加其他conda环境的方法&#xff0c;远程密码调用jupyter的方法&#xff0c;修改jupyter工作目录的方法。 文章目录 一、入门级配置1. Pycharm配置Conda自带的jupyt…...

企业微信ipad版,http协议接口发开,获取客户群列表

版本介绍&#xff1a; HTTP协议接口可以通过该接口实现企业微信的各种功能&#xff0c;使用HTTP协议可以避免使用hook形式的需要开启PC客户端的方式&#xff0c;同时可以实现三端同时在线&#xff0c;不影响PC和手机端的登录状态&#xff0c;调用简单&#xff0c;可以支持几千…...

Double 4 VR智能互动教学系统在小语种课堂中的教学应用

小语种课堂一直是教育领域的一个难点。由于语言本身的复杂性和文化背景的差异&#xff0c;小语种教学一直是一个挑战。传统的课堂教学方法往往难以激发学生的学习兴趣和动力&#xff0c;教学效果不尽如人意。而Double 4 VR智能互动教学系统为小语种课堂带来了新的可能。 Double…...

OSEK OS任务调度的底层逻辑

先参考 FreeRTOS的任务触发底层逻辑 简述RTOS任务调度底层逻辑 AUTOSAR-OS的调度机制-调度表&#xff08;没理解透&#xff0c;继续更新&#xff09; OSEK与FreeRTOS在任务调度上最大的区别在于&#xff0c;FreeRTOS是基于全抢占任务调度和时间片轮转调度机制&#xff0c;具有…...

‘tsc‘ 不是内部或外部命令,也不是可运行的程序 或批处理文件。

最近在用nodejs typescript 某游戏服务器在做一些研究 nodejs-tcs 问题描述&#xff1a; 1.使用命令npm install -g typescript安装typescript后&#xff0c;输入 tsc命令&#xff0c;一直报错 tsc 不是内部或外部命令&#xff0c;也不是可运行的程序 或批处理文件。 2.目…...

windows文件删除权限

一、普通文件 这里指的是所有可以被随意删除的文件。 二、可更改权限的文件 如果想要删除的文件无法被删除&#xff0c;那大概是权限不够&#xff0c;这时候&#xff1a;鼠标右键、属性、安全、编辑、选择相应的组或用户&#xff08;如果不知道哪个可以全选&#xff0c;反正…...

uniapp 对接腾讯云IM群组成员管理(增删改查)

UniApp 实战&#xff1a;腾讯云IM群组成员管理&#xff08;增删改查&#xff09; 一、前言 在社交类App开发中&#xff0c;群组成员管理是核心功能之一。本文将基于UniApp框架&#xff0c;结合腾讯云IM SDK&#xff0c;详细讲解如何实现群组成员的增删改查全流程。 权限校验…...

龙虎榜——20250610

上证指数放量收阴线&#xff0c;个股多数下跌&#xff0c;盘中受消息影响大幅波动。 深证指数放量收阴线形成顶分型&#xff0c;指数短线有调整的需求&#xff0c;大概需要一两天。 2025年6月10日龙虎榜行业方向分析 1. 金融科技 代表标的&#xff1a;御银股份、雄帝科技 驱动…...

Java多线程实现之Callable接口深度解析

Java多线程实现之Callable接口深度解析 一、Callable接口概述1.1 接口定义1.2 与Runnable接口的对比1.3 Future接口与FutureTask类 二、Callable接口的基本使用方法2.1 传统方式实现Callable接口2.2 使用Lambda表达式简化Callable实现2.3 使用FutureTask类执行Callable任务 三、…...

如何将联系人从 iPhone 转移到 Android

从 iPhone 换到 Android 手机时&#xff0c;你可能需要保留重要的数据&#xff0c;例如通讯录。好在&#xff0c;将通讯录从 iPhone 转移到 Android 手机非常简单&#xff0c;你可以从本文中学习 6 种可靠的方法&#xff0c;确保随时保持连接&#xff0c;不错过任何信息。 第 1…...

TRS收益互换:跨境资本流动的金融创新工具与系统化解决方案

一、TRS收益互换的本质与业务逻辑 &#xff08;一&#xff09;概念解析 TRS&#xff08;Total Return Swap&#xff09;收益互换是一种金融衍生工具&#xff0c;指交易双方约定在未来一定期限内&#xff0c;基于特定资产或指数的表现进行现金流交换的协议。其核心特征包括&am…...

laravel8+vue3.0+element-plus搭建方法

创建 laravel8 项目 composer create-project --prefer-dist laravel/laravel laravel8 8.* 安装 laravel/ui composer require laravel/ui 修改 package.json 文件 "devDependencies": {"vue/compiler-sfc": "^3.0.7","axios": …...

Reasoning over Uncertain Text by Generative Large Language Models

https://ojs.aaai.org/index.php/AAAI/article/view/34674/36829https://ojs.aaai.org/index.php/AAAI/article/view/34674/36829 1. 概述 文本中的不确定性在许多语境中传达,从日常对话到特定领域的文档(例如医学文档)(Heritage 2013;Landmark、Gulbrandsen 和 Svenevei…...

C++使用 new 来创建动态数组

问题&#xff1a; 不能使用变量定义数组大小 原因&#xff1a; 这是因为数组在内存中是连续存储的&#xff0c;编译器需要在编译阶段就确定数组的大小&#xff0c;以便正确地分配内存空间。如果允许使用变量来定义数组的大小&#xff0c;那么编译器就无法在编译时确定数组的大…...

视觉slam十四讲实践部分记录——ch2、ch3

ch2 一、使用g++编译.cpp为可执行文件并运行(P30) g++ helloSLAM.cpp ./a.out运行 二、使用cmake编译 mkdir build cd build cmake .. makeCMakeCache.txt 文件仍然指向旧的目录。这表明在源代码目录中可能还存在旧的 CMakeCache.txt 文件,或者在构建过程中仍然引用了旧的路…...

关于uniapp展示PDF的解决方案

在 UniApp 的 H5 环境中使用 pdf-vue3 组件可以实现完整的 PDF 预览功能。以下是详细实现步骤和注意事项&#xff1a; 一、安装依赖 安装 pdf-vue3 和 PDF.js 核心库&#xff1a; npm install pdf-vue3 pdfjs-dist二、基本使用示例 <template><view class"con…...