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);//............
};

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

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

相关文章

CSS的filter属性详解

目录 前言 函数 blur()函数 brightness()函数 contrast()函数 drop-shadow()函数 grayscale()函数 hue-rotate() (en-US)函数 invert() (en-US)函数 opacity()函数 saturate() (en-US)函数 sepia() (en-US)函数 组合函数 前言 CSS的filter 属性将模糊或颜色偏移等…

【正点原子STM32连载】 第六十一章 USB读卡器(Slave)实验摘自【正点原子】APM32F407最小系统板使用指南

1&#xff09;实验平台&#xff1a;正点原子APM32F407最小系统板 2&#xff09;平台购买地址&#xff1a;https://detail.tmall.com/item.htm?id609294757420 3&#xff09;全套实验源码手册视频下载地址&#xff1a; http://www.openedv.com/thread-340252-1-1.html## 第六十…

Electronica慕尼黑电子展 Samtec团队与21ic分享虎家产品与方案

【摘要/前言】 “希望但凡是能够使用到连接器的场合都有Samtec的身影” 在慕尼黑上海电子展现场&#xff0c;Samtec华东区销售经理章桢彦先生在与21ic副主编刘岩轩老师的采访中&#xff0c;如是说道。这是一种愿景&#xff0c;更是Samtec的努力方向。短短一句话&#xff0c;…

视频播放标签,设置自动播放 暂停键 播放键 js方法

1 创建video 标签&#xff0c;标签设置属性 autoplay 自动播放&#xff0c;宽高100 全屏。 <video class"video" id"shipin" controls"controls" autoplay poster"" style"width:100%;height:100%;position:fixed;">&…

notepad++ 插件JSONView安装

1&#xff0c;前提 开发过程中经常需要处理json格式语句&#xff0c;需要对json数据格式化处理&#xff0c;因为使用的是虚拟机内开发&#xff0c;所以没法连接外网&#xff0c;只能在本地电脑下载插件后&#xff0c;然后上传到虚拟机中&#xff0c;进行安装使用。 2&#xf…

1+x中级网络运维实验题

任务 1&#xff1a; 设备命名 为了方便后期维护和故障定位及网络的规范性&#xff0c;需要对网络设备进行规范化命名。请根据 Figure 3-1 实验考试拓扑对设备进行命名。命名规则为&#xff1a;城市-设备的设置地点-设备的功能属性和序号-设备型号。例如&#xff1a;处于杭州校…

@Autowired注解获取对象为null

问题再现 兄弟们&#xff0c;看见了吗&#xff1f;这里我Autowired进来的forkliftService 居然为null 且我SysForkliftServiceImpl上面是加了Service注解的 分析原因 主要原因就是因为该类继承了一个第三方框架SimpleChannelInboundHandler&#xff0c;在执行的过程中&#…

[Java 源码] 美团一面~ArrayList 的底层实现

文章目录 1. ArrayList 与 数组的区别2 ArrayList 的初始化容量3. ArrayList 的扩容具体指什么4. ArrayList是如何实现扩容的&#xff1f;5. ArrayList有缩容吗&#xff1f; 1. ArrayList 与 数组的区别 ArrayList 的底层是数组队列&#xff0c;相当于动态数组。与 Java 中的数…

2023年【P气瓶充装】找解析及P气瓶充装复审模拟考试

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 P气瓶充装找解析参考答案及P气瓶充装考试试题解析是安全生产模拟考试一点通题库老师及P气瓶充装操作证已考过的学员汇总&#xff0c;相对有效帮助P气瓶充装复审模拟考试学员顺利通过考试。 1、【多选题】CNG双燃料汽车…

Dockerfile 与 Docker Compose区别

目录 Dockerfile Docker Compose 综合比较 Dockerfile 用途&#xff1a; Dockerfile 用于定义单个容器的构建过程。它包含了一系列指令&#xff0c;每个指令都代表容器构建过程中的一个步骤。这些步骤包括从基础镜像中构建、安装依赖、拷贝文件、设置环境变量等操作。 语法…

【IEEE独立出版】2024第四届神经网络、信息与通信工程国际学术会议(NNICE 2024)

2024第四届神经网络、信息与通信工程国际学术会议&#xff08;NNICE 2024&#xff09; 2024 4th International Conference on Neural Networks, Information and Communication Engineering 2024第四神经网络、信息与通信工程国际学术会议&#xff08;NNICE 2024&#xff0…

电商API接口对于实现电商系统平台的搭建有哪些作用?

电商API接口用于实现电商平台的数据交互和功能调用。具体来说&#xff0c;电商API接口可以用于以下几个方面&#xff1a; 1. 商品管理&#xff1a;通过API接口&#xff0c;可以实现商品的添加、修改、删除、查询等操作。商家可以通过API接口将自己的商品信息上传到电商平台&…

三、Linux高级命令

目录 1、重定向命令 1.1 重定向 > 1.2 重定向 >> 该章节的所有操作都在/export/data/shell目录进行&#xff0c;请提前创建该目录。 mkdir -p /export/data/ 1、重定向命令 1.1 重定向 > Linux 允许将命令执行结果重定向到一个文件&#xff0c;本应显示在…

群晖NAS:docker(Container Manager)、npm安装Verdaccio并常见命令集合

群晖NAS&#xff1a;docker&#xff08;Container Manager&#xff09;、npm安装Verdaccio并常见命令集合 自建 npm 资源库&#xff0c;使用Verdaccio。如果觉得麻烦&#xff0c;直接可以在外网注册 https://www.npmjs.com/ 网站。大同小异&#xff0c;自己搭建搭建方便局域网…

虾皮、Lazada稳定的测评系统需要哪些技术要求

测评作为一项高效运营手段&#xff0c;具有显著的重要性。然而&#xff0c;对于卖家而言&#xff0c;自行建立一套测评系统所需的技术条件并非易事。 在构建系统之前&#xff0c;必须深入理解每个平台的控制风险机制&#xff0c;而后才能开展下一步的建设工作。 1.首先&#…

代币化:2024年的金融浪潮预示着什么?

自“TradFi”领袖到加密专家&#xff0c;各方预测代币化机会高达数十万亿。虽然已有引人注目的用例&#xff0c;但与未来几年可能在链上转移的大量数字化资产相比&#xff0c;这些仅是冰山一角。 代币化何时会变为洪流&#xff1f;什么阻碍了其发展&#xff1f; 今年10月&…

SpringBoot下使用Quartz设置定时任务

SpringBoot下使用Quartz设置定时任务 基础使用添加依赖demo 基础使用 Quartz 的核心类有以下三部分&#xff1a; 任务 Job &#xff1a; 需要实现的任务类&#xff0c;实现 execute() 方法&#xff0c;执行后完成任务。触发器 Trigger &#xff1a; 包括 SimpleTrigger 和 Cr…

VGN S99快捷键,说明书

VGN S99快捷键-说明书 按键说明灯光效果常见疑难 按键说明 切换关闭电量指示灯&#xff1a;Fn home 灯光效果 常见疑难

服务器,数据库服务器各指标怎么看?

一&#xff09;服务器&#xff1a; 1&#xff09; 系统负载 load 1m,load 5m,load 15m分别是什么意思&#xff1f; 1m 表示过去 1 分钟的平均负载&#xff0c;5m 表示过去 5 分钟的平均负载&#xff0c;15m 表示过去 15 分钟的平均负载。系统负载是指系统在过去一段时间内处理的…

GPT5大剧第二季开启,Sam Altman 重掌 OpenAI CEO 大权

OpenAl 最新公告: Sam Altman 重掌 OpenAI CEO 大权&#xff0c;公司迎来新的初始董事会 Mira Murati 出任 CTO,Greg Brockman 再次成为总裁。来看看CEO Sam Altman和董事会主席 Bret Taylor的最新发言。 2023年11月29日 以下是 CEO Sam Altman和董事会主席 Bret Taylor 今天下…