当前位置: 首页 > 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;反正…...

椭圆曲线密码学(ECC)

一、ECC算法概述 椭圆曲线密码学&#xff08;Elliptic Curve Cryptography&#xff09;是基于椭圆曲线数学理论的公钥密码系统&#xff0c;由Neal Koblitz和Victor Miller在1985年独立提出。相比RSA&#xff0c;ECC在相同安全强度下密钥更短&#xff08;256位ECC ≈ 3072位RSA…...

模型参数、模型存储精度、参数与显存

模型参数量衡量单位 M&#xff1a;百万&#xff08;Million&#xff09; B&#xff1a;十亿&#xff08;Billion&#xff09; 1 B 1000 M 1B 1000M 1B1000M 参数存储精度 模型参数是固定的&#xff0c;但是一个参数所表示多少字节不一定&#xff0c;需要看这个参数以什么…...

《用户共鸣指数(E)驱动品牌大模型种草:如何抢占大模型搜索结果情感高地》

在注意力分散、内容高度同质化的时代&#xff0c;情感连接已成为品牌破圈的关键通道。我们在服务大量品牌客户的过程中发现&#xff0c;消费者对内容的“有感”程度&#xff0c;正日益成为影响品牌传播效率与转化率的核心变量。在生成式AI驱动的内容生成与推荐环境中&#xff0…...

vue3 字体颜色设置的多种方式

在Vue 3中设置字体颜色可以通过多种方式实现&#xff0c;这取决于你是想在组件内部直接设置&#xff0c;还是在CSS/SCSS/LESS等样式文件中定义。以下是几种常见的方法&#xff1a; 1. 内联样式 你可以直接在模板中使用style绑定来设置字体颜色。 <template><div :s…...

【论文笔记】若干矿井粉尘检测算法概述

总的来说&#xff0c;传统机器学习、传统机器学习与深度学习的结合、LSTM等算法所需要的数据集来源于矿井传感器测量的粉尘浓度&#xff0c;通过建立回归模型来预测未来矿井的粉尘浓度。传统机器学习算法性能易受数据中极端值的影响。YOLO等计算机视觉算法所需要的数据集来源于…...

【Linux】Linux 系统默认的目录及作用说明

博主介绍&#xff1a;✌全网粉丝23W&#xff0c;CSDN博客专家、Java领域优质创作者&#xff0c;掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域✌ 技术范围&#xff1a;SpringBoot、SpringCloud、Vue、SSM、HTML、Nodejs、Python、MySQL、PostgreSQL、大数据、物…...

mac 安装homebrew (nvm 及git)

mac 安装nvm 及git 万恶之源 mac 安装这些东西离不开Xcode。及homebrew 一、先说安装git步骤 通用&#xff1a; 方法一&#xff1a;使用 Homebrew 安装 Git&#xff08;推荐&#xff09; 步骤如下&#xff1a;打开终端&#xff08;Terminal.app&#xff09; 1.安装 Homebrew…...

【C++进阶篇】智能指针

C内存管理终极指南&#xff1a;智能指针从入门到源码剖析 一. 智能指针1.1 auto_ptr1.2 unique_ptr1.3 shared_ptr1.4 make_shared 二. 原理三. shared_ptr循环引用问题三. 线程安全问题四. 内存泄漏4.1 什么是内存泄漏4.2 危害4.3 避免内存泄漏 五. 最后 一. 智能指针 智能指…...

MacOS下Homebrew国内镜像加速指南(2025最新国内镜像加速)

macos brew国内镜像加速方法 brew install 加速formula.jws.json下载慢加速 &#x1f37a; 最新版brew安装慢到怀疑人生&#xff1f;别怕&#xff0c;教你轻松起飞&#xff01; 最近Homebrew更新至最新版&#xff0c;每次执行 brew 命令时都会自动从官方地址 https://formulae.…...

SQL Server 触发器调用存储过程实现发送 HTTP 请求

文章目录 需求分析解决第 1 步:前置条件,启用 OLE 自动化方式 1:使用 SQL 实现启用 OLE 自动化方式 2:Sql Server 2005启动OLE自动化方式 3:Sql Server 2008启动OLE自动化第 2 步:创建存储过程第 3 步:创建触发器扩展 - 如何调试?第 1 步:登录 SQL Server 2008第 2 步…...