qt creator源码全方面分析(4-5)
Qt中的字符串
Qt中处理字符串最常用的肯定是QString,但是在qt creator源码中出现了大量的QLatin1String。下面我们来介绍下区别。
QLatinString
详细介绍
我们首先来看QLatinString。类详细介绍如下:
QString的许多成员函数都被重载以接受const char *而不是QString。 这包括复制构造函数,赋值运算符,比较运算符以及各种其他函数,例如insert(),replace()和indexOf()。 这些函数通常经过优化,以避免为const char *数据构造QString对象。 例如,假设str是QString,
QLatin1String类为US-ASCII/Latin-1编码的字符串文字提供了一个小型包装器。
QString的许多成员函数都被重载以接受const char *参数而不是QString参数。 这包括复制构造函数,赋值运算符,比较运算符以及各种其他函数,例如insert(),replace()和indexOf()。 这些函数通常经过优化,以避免为const char *数据构造QString对象。 例如,假设str是QString,
if (str == "auto" || str == "extern"
|| str == "static" || str == "register") {
...
}
比下面的快很多
if (str == QString("auto") || str == QString("extern")
|| str == QString("static") || str == QString("register")) {
...
}
因为它不会构造四个临时QString对象并进行字符数据的深拷贝。
定义QT_NO_CAST_FROM_ASCII宏(如QString文档中所述)的应用程序无法访问QString的const char * 接口API。为了提供一种指定常量Latin-1字符串的有效方法,Qt提供了QLatin1String,它是const char *的非常薄的包装。使用QLatin1String,上面的示例代码变为
if (str == QLatin1String("auto")
|| str == QLatin1String("extern")
|| str == QLatin1String("static")
|| str == QLatin1String("register") {
...
}
键入的时间稍长一些,但是它提供的功能与代码的第一个版本完全相同,并且比使用QString::fromLatin1()转换Latin-1字符串的速度更快。
多亏了QString(QLatin1String)构造函数,QLatin1String可以在需要QString的任何地方使用。 例如:
QLabel *label = new QLabel(QLatin1String("MOD"), this);
注意:如果你调用的函数,使用QLatin1String作为参数,实际上并未被重载来使用QLatin1String,而是进行QString的隐式转换,并将触发内存分配,而这是你通常使用QLatin1String首先要避免的情况。在这些情况下,使用QStringLiteral可能是更好的选择。
源码
我们看下QLatin1String源码,进行了截取,展现核心部分
class QLatin1String
{
public:
inline QLatin1String() : m_size(0), m_data(nullptr) {}
inline explicit QLatin1String(const char *s) : m_size(s ? int(strlen(s)) : 0), m_data(s) {}
private:
int m_size;
const char *m_data;
}
我们可以发现,真的是简单的包装,也没有什么深拷贝什么的,只是把地址简单的赋给了成员变量m_data。
小结
简单说,QLatin1String就是对const char*的简单包装,用在QT_NO_CAST_FROM_ASCII导致无法访问QString的const char*接口的地方。
QStringLiteral(str)
QString这个大家都很熟悉了,我们也不过多介绍。这里提一下QStringLiteral,大家可以在QString类介绍中找到。
详细介绍
这是一个宏,在编译时从字符串文字str中为QString生成数据。 在这种情况下,可以免费创建QString,并且将生成的字符串数据存储在已编译目标文件的只读段中。
如果您的代码如下所示:
// hasAttribute takes a QString argument
if (node.hasAttribute("http-contents-length")) //...
然后这将创建一个临时QString作为hasAttribute函数参数进行传递。 这可能会非常昂贵,因为它涉及内存分配以及将数据复制/转换为QString的内部编码。
通过使用QStringLiteral可以避免此成本:
if (node.hasAttribute(QStringLiteral(u"http-contents-length"))) //...
在这种情况下,QString的内部数据将在编译时生成。在运行时不会发生任何转换或分配。
使用QStringLiteral而不是用双引号引起来的纯C++字符串文字,可以显着加快根据编译时已知的数据创建QString实例的速度。
注意:当将字符串传递给具有重载QLatin1String参数的函数时,QLatin1String仍比QStringLiteral更有效,并且此重载避免了转换为QString。例如,QString::operator ==()可以直接与QLatin1String进行比较:
if (attribute.name() == QLatin1String("http-contents-length")) //...
注意:某些编译器编码包含US-ASCII字符集以外字符的字符串会有bug。在这种情况下,请确保在字符串前加上u。否则是可选的。
源码
我们查看宏定义源码
template <int N>
struct QStaticStringData
{
QArrayData str;
qunicodechar data[N + 1];
QStringData *data_ptr() const
{
Q_ASSERT(str.ref.isStatic());
return const_cast<QStringData *>(static_cast<const QStringData*>(&str));
}
};
struct Q_CORE_EXPORT QArrayData
{
QtPrivate::RefCount ref;
int size;
uint alloc : 31;
uint capacityReserved : 1;
qptrdiff offset; // in bytes from beginning of header
}
#define QStringLiteral(str) \
([]() Q_DECL_NOEXCEPT -> QString { \
enum { Size = sizeof(QT_UNICODE_LITERAL(str))/2 - 1 }; \
static const QStaticStringData<Size> qstring_literal = { \
Q_STATIC_STRING_DATA_HEADER_INITIALIZER(Size), \
QT_UNICODE_LITERAL(str) }; \
QStringDataPtr holder = { qstring_literal.data_ptr() }; \
const QString qstring_literal_temp(holder); \
return qstring_literal_temp; \
}())
#define Q_STATIC_STRING_DATA_HEADER_INITIALIZER_WITH_OFFSET(size, offset) \
{ Q_REFCOUNT_INITIALIZE_STATIC, size, 0, 0, offset }
#define Q_STATIC_STRING_DATA_HEADER_INITIALIZER(size) \
Q_STATIC_STRING_DATA_HEADER_INITIALIZER_WITH_OFFSET(size, sizeof(QStringData))
我们对Q_STATIC_STRING_DATA_HEADER_INITIALIZER宏进行替换,可以得到
#define QStringLiteral(str) \
([]() Q_DECL_NOEXCEPT -> QString { \
// 计算大小,unicode为16bit一个字符,所以除2
enum { Size = sizeof(QT_UNICODE_LITERAL(str))/2 - 1 }; \
// 核心,只读静态变量,POD结构,编译器创建
static const QStaticStringData<Size> qstring_literal = { \
// QArrayData
{-1, \
size, \
0, \
0, \
sizeof(QStringData) \
}, \
// qunicodechar []
QT_UNICODE_LITERAL(str) }; \
// 获取编译器创建的静态底层数据
QStringDataPtr holder = { qstring_literal.data_ptr() }; \
// 构造QString,不用进行内存分配了
const QString qstring_literal_temp(holder); \
// 返回QString,完成加速
return qstring_literal_temp; \
}())
小结
说白了,QStringLiteral在编译期就创建了数据,避免了内存分配,加速了QString的创建。
原创造福大家,共享改变世界
献出一片爱心,温暖作者心灵

qt creator源码全方面分析(4-5)的更多相关文章
- qt creator源码全方面分析(3-3)
目录 qtcreatordata.pri 定义stripStaticBase替换函数 设置自定义编译和安装 QMAKE_EXTRA_COMPILERS Adding Compilers 示例1 示例2 ...
- qt creator源码全方面分析(3-5)
目录 qtcreatorlibrary.pri 使用实例 上半部 下半部 结果 qtcreatorlibrary.pri 上一章节,我们介绍了src.pro,这里乘此机会,把src目录下的所有项目文件 ...
- qt creator源码全方面分析(0)
本人主攻C++和Qt. 上两天刚研究完Qt install framework(IFW)应用程序安装框架. google没发现有正儿八经的官方文档的翻译,我就进行了翻译哈!! 系列文章具体见:http ...
- qt creator源码全方面分析(4-0)
Qt系统 Qt Creator源码是在Qt对象和框架基础下写的,因此,阅读Qt Creator源码,你首先对Qt得有一定的了解. Qt Core Qt Core特征: The Meta-Object ...
- qt creator源码全方面分析(4-2)
目录 global头文件 global.h xx.h global头文件 插件的本质就是动态链接库,对于库,需要导出符号,供用户导入使用.在qt creator的源码中,存在固定的导入导出模式. gl ...
- qt creator源码全方面分析(4-6)
目录 Qt插件基础 Qt插件基础 我们知道Qt Creator源码是基于插件架构的,那么我们先来介绍下插件基础知识. 相关内容如下: How to Create Qt Plugins [ - Defi ...
- qt creator源码全方面分析(3-2)
目录 qtcreator.pri 判断重复包含 定义版本信息 VERSION 定义IDE名称 启用C++14 CONFIG 自定义函数 Replace Functions Test Functions ...
- qt creator源码全方面分析(2-7)
目录 Completing Code 补全代码片段 编辑代码片段 添加和编辑片段 删除片段 重置片段 补全Nim代码 Completing Code 在编写代码时,Qt Creator建议使用属性,I ...
- qt creator源码全方面分析(2-10-1)
目录 Getting and Building Qt Creator 获取Qt 获取和构建Qt Creator Getting and Building Qt Creator 待办事项:应该对此进行扩 ...
随机推荐
- 你知道如何自动保存 Spring Boot 应用进程号吗
1. 前言 欢迎阅读 Spring Boot 2 实战 系列文章. PID 对于系统运维来说并不陌生,但是对于一些开发者特别是新手还是要简单介绍一下的.它是 Process ID 的简称,是系统分配给 ...
- day7作业
# day7作业 # 1. 使用while循环输出1 2 3 4 5 6 8 9 10 count = 1 while count < 11: if count == 7: count += 1 ...
- Python程序设计 实验 1 熟悉 IDLE 和在线编程平台
------------恢复内容开始------------ 安徽工程大学 Python程序设计 实验报告 班级 物流191 姓名 姚彩琴 学号3190505129 成绩 日期 2 ...
- D. 蚂蚁平面
D. 蚂蚁平面 单点时限: 2.0 sec 内存限制: 512 MB 平面上有 n只蚂蚁,它走过的路径可以看作一条直线 由这n 条直线定义的某些区域是无界的,而另一些区域则是有界的. 有界区域的最大个 ...
- A 蚂蚁觅食
A. 蚂蚁觅食(一) 单点时限: 1.0 sec 内存限制: 512 MB 一只饥饿的小蚂蚁外出觅食,幸运的小蚂蚁发现了好多食物,但是它只有一次搬食物的机会.可因为力气太小了,它不能搬走重量超过自己体 ...
- 10.添加script标签,判断onload是否完成
class Tools { static loadScript(url, callback) { let old_script = document.getElementById(url); if ( ...
- [PHP] excel 的导入导出
其实excel导入导出挺简单的,导出最简单! 其原理都是把数据读出来,导出是从数据库中读出数据,导入是从文件读出数据! 导出写入文件,导入写入数据库! 但是在导入表的时候,用的是PHPExcel, 不 ...
- 《并发编程的艺术》阅读笔记之Lock与AQS
Lock接口 在jdk1.5之后,并发包下新增了一个lock接口,lock接口定义了锁的获取,锁的释放,等方法,需要用户手动设置.与关键字不同的是,lock具有可操作性,比如,可以中断线程,设置超时时 ...
- Playbook中标签的使用(五)
一个playbook文件中,执行时如果想执行某一个任务,那么可以给每个任务集进行打标签,这样在执行的时候可以通过-t选择指定标签执行, 还可以通过--skip-tags选择除了某个标签外全部执行等 [ ...
- (转)SQLite数据库的加密
1.创建空的SQLite数据库. //数据库名的后缀你可以直接指定,甚至没有后缀都可以 //方法一:创建一个空sqlite数据库,用IO的方式 FileStream fs = File.Create( ...