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,

  1. if (str == "auto" || str == "extern"
  2. || str == "static" || str == "register") {
  3. ...
  4. }

比下面的快很多

  1. if (str == QString("auto") || str == QString("extern")
  2. || str == QString("static") || str == QString("register")) {
  3. ...
  4. }

因为它不会构造四个临时QString对象并进行字符数据的深拷贝。

定义QT_NO_CAST_FROM_ASCII宏(如QString文档中所述)的应用程序无法访问QString的const char * 接口API。为了提供一种指定常量Latin-1字符串的有效方法,Qt提供了QLatin1String,它是const char *的非常薄的包装。使用QLatin1String,上面的示例代码变为

  1. if (str == QLatin1String("auto")
  2. || str == QLatin1String("extern")
  3. || str == QLatin1String("static")
  4. || str == QLatin1String("register") {
  5. ...
  6. }

键入的时间稍长一些,但是它提供的功能与代码的第一个版本完全相同,并且比使用QString::fromLatin1()转换Latin-1字符串的速度更快。

多亏了QString(QLatin1String)构造函数,QLatin1String可以在需要QString的任何地方使用。 例如:

  1. QLabel *label = new QLabel(QLatin1String("MOD"), this);

注意:如果你调用的函数,使用QLatin1String作为参数,实际上并未被重载来使用QLatin1String,而是进行QString的隐式转换,并将触发内存分配,而这是你通常使用QLatin1String首先要避免的情况。在这些情况下,使用QStringLiteral可能是更好的选择。

源码

我们看下QLatin1String源码,进行了截取,展现核心部分

  1. class QLatin1String
  2. {
  3. public:
  4. inline QLatin1String() : m_size(0), m_data(nullptr) {}
  5. inline explicit QLatin1String(const char *s) : m_size(s ? int(strlen(s)) : 0), m_data(s) {}
  6. private:
  7. int m_size;
  8. const char *m_data;
  9. }

我们可以发现,真的是简单的包装,也没有什么深拷贝什么的,只是把地址简单的赋给了成员变量m_data。

小结

简单说,QLatin1String就是对const char*的简单包装,用在QT_NO_CAST_FROM_ASCII导致无法访问QString的const char*接口的地方。

QStringLiteral(str)

QString这个大家都很熟悉了,我们也不过多介绍。这里提一下QStringLiteral,大家可以在QString类介绍中找到。

详细介绍

这是一个宏,在编译时从字符串文字str中为QString生成数据。 在这种情况下,可以免费创建QString,并且将生成的字符串数据存储在已编译目标文件的只读段中。

如果您的代码如下所示:

  1. // hasAttribute takes a QString argument
  2. if (node.hasAttribute("http-contents-length")) //...

然后这将创建一个临时QString作为hasAttribute函数参数进行传递。 这可能会非常昂贵,因为它涉及内存分配以及将数据复制/转换为QString的内部编码。

通过使用QStringLiteral可以避免此成本:

  1. if (node.hasAttribute(QStringLiteral(u"http-contents-length"))) //...

在这种情况下,QString的内部数据将在编译时生成。在运行时不会发生任何转换或分配。

使用QStringLiteral而不是用双引号引起来的纯C++字符串文字,可以显着加快根据编译时已知的数据创建QString实例的速度。

注意:当将字符串传递给具有重载QLatin1String参数的函数时,QLatin1String仍比QStringLiteral更有效,并且此重载避免了转换为QString。例如,QString::operator ==()可以直接与QLatin1String进行比较:

  1. if (attribute.name() == QLatin1String("http-contents-length")) //...

注意:某些编译器编码包含US-ASCII字符集以外字符的字符串会有bug。在这种情况下,请确保在字符串前加上u。否则是可选的。

源码

我们查看宏定义源码

  1. template <int N>
  2. struct QStaticStringData
  3. {
  4. QArrayData str;
  5. qunicodechar data[N + 1];
  6. QStringData *data_ptr() const
  7. {
  8. Q_ASSERT(str.ref.isStatic());
  9. return const_cast<QStringData *>(static_cast<const QStringData*>(&str));
  10. }
  11. };
  12. struct Q_CORE_EXPORT QArrayData
  13. {
  14. QtPrivate::RefCount ref;
  15. int size;
  16. uint alloc : 31;
  17. uint capacityReserved : 1;
  18. qptrdiff offset; // in bytes from beginning of header
  19. }
  20. #define QStringLiteral(str) \
  21. ([]() Q_DECL_NOEXCEPT -> QString { \
  22. enum { Size = sizeof(QT_UNICODE_LITERAL(str))/2 - 1 }; \
  23. static const QStaticStringData<Size> qstring_literal = { \
  24. Q_STATIC_STRING_DATA_HEADER_INITIALIZER(Size), \
  25. QT_UNICODE_LITERAL(str) }; \
  26. QStringDataPtr holder = { qstring_literal.data_ptr() }; \
  27. const QString qstring_literal_temp(holder); \
  28. return qstring_literal_temp; \
  29. }())
  30. #define Q_STATIC_STRING_DATA_HEADER_INITIALIZER_WITH_OFFSET(size, offset) \
  31. { Q_REFCOUNT_INITIALIZE_STATIC, size, 0, 0, offset }
  32. #define Q_STATIC_STRING_DATA_HEADER_INITIALIZER(size) \
  33. Q_STATIC_STRING_DATA_HEADER_INITIALIZER_WITH_OFFSET(size, sizeof(QStringData))

我们对Q_STATIC_STRING_DATA_HEADER_INITIALIZER宏进行替换,可以得到

  1. #define QStringLiteral(str) \
  2. ([]() Q_DECL_NOEXCEPT -> QString { \
  3. // 计算大小,unicode为16bit一个字符,所以除2
  4. enum { Size = sizeof(QT_UNICODE_LITERAL(str))/2 - 1 }; \
  5. // 核心,只读静态变量,POD结构,编译器创建
  6. static const QStaticStringData<Size> qstring_literal = { \
  7. // QArrayData
  8. {-1, \
  9. size, \
  10. 0, \
  11. 0, \
  12. sizeof(QStringData) \
  13. }, \
  14. // qunicodechar []
  15. QT_UNICODE_LITERAL(str) }; \
  16. // 获取编译器创建的静态底层数据
  17. QStringDataPtr holder = { qstring_literal.data_ptr() }; \
  18. // 构造QString,不用进行内存分配了
  19. const QString qstring_literal_temp(holder); \
  20. // 返回QString,完成加速
  21. return qstring_literal_temp; \
  22. }())

小结

说白了,QStringLiteral在编译期就创建了数据,避免了内存分配,加速了QString的创建。


原创造福大家,共享改变世界

献出一片爱心,温暖作者心灵


qt creator源码全方面分析(4-5)的更多相关文章

  1. qt creator源码全方面分析(3-3)

    目录 qtcreatordata.pri 定义stripStaticBase替换函数 设置自定义编译和安装 QMAKE_EXTRA_COMPILERS Adding Compilers 示例1 示例2 ...

  2. qt creator源码全方面分析(3-5)

    目录 qtcreatorlibrary.pri 使用实例 上半部 下半部 结果 qtcreatorlibrary.pri 上一章节,我们介绍了src.pro,这里乘此机会,把src目录下的所有项目文件 ...

  3. qt creator源码全方面分析(0)

    本人主攻C++和Qt. 上两天刚研究完Qt install framework(IFW)应用程序安装框架. google没发现有正儿八经的官方文档的翻译,我就进行了翻译哈!! 系列文章具体见:http ...

  4. qt creator源码全方面分析(4-0)

    Qt系统 Qt Creator源码是在Qt对象和框架基础下写的,因此,阅读Qt Creator源码,你首先对Qt得有一定的了解. Qt Core Qt Core特征: The Meta-Object ...

  5. qt creator源码全方面分析(4-2)

    目录 global头文件 global.h xx.h global头文件 插件的本质就是动态链接库,对于库,需要导出符号,供用户导入使用.在qt creator的源码中,存在固定的导入导出模式. gl ...

  6. qt creator源码全方面分析(4-6)

    目录 Qt插件基础 Qt插件基础 我们知道Qt Creator源码是基于插件架构的,那么我们先来介绍下插件基础知识. 相关内容如下: How to Create Qt Plugins [ - Defi ...

  7. qt creator源码全方面分析(3-2)

    目录 qtcreator.pri 判断重复包含 定义版本信息 VERSION 定义IDE名称 启用C++14 CONFIG 自定义函数 Replace Functions Test Functions ...

  8. qt creator源码全方面分析(2-7)

    目录 Completing Code 补全代码片段 编辑代码片段 添加和编辑片段 删除片段 重置片段 补全Nim代码 Completing Code 在编写代码时,Qt Creator建议使用属性,I ...

  9. qt creator源码全方面分析(2-10-1)

    目录 Getting and Building Qt Creator 获取Qt 获取和构建Qt Creator Getting and Building Qt Creator 待办事项:应该对此进行扩 ...

随机推荐

  1. stand up meeting 12/22/2015 && 用户体验收录

    part 组员                工作              工作耗时/h 明日计划 工作耗时/h    UI 冯晓云  完善页面切换,尝试子页面设计    4  完善页面切换和子页面 ...

  2. 牛客练习赛61 相似的子串(二分+Hash)

    题面在此 题解:将字符串分成k部分,然后求最长前缀,所以我们只关注前缀部分就好了,公共前缀后边的是啥不用管,那么问题就转化成了是否存在k个不相交的字符串的最长公共前缀问题.首先用Hash来记录一下字符 ...

  3. G - Messy codeforces1262C

    题目大意: 输入n和m,n是n个字符,m是m个前缀.对前缀的规定可以配对的括号.比如(),,((()))等等.在输入n个括号字符,对这个n个字符,通过交换使其满足m个前缀.交换次数不限,规则想当与re ...

  4. NK16

    C 小石的海岛之旅 链接:https://ac.nowcoder.com/acm/contest/949/C来源:牛客网 暑假到了,小石和小雨到海岛上玩. 从水平方向看海岛可以看成 nnn个小块,每一 ...

  5. linq 高集成化数据访问技术

    一:  新建名为linq的项目 创建 linq 1 在项目里添加文件夹 App_Code; 2 在文件夹(App_Code) 添加  名为db的    Linq To Sql 类  :一个Linq T ...

  6. 参数化parameterized

    pip install parameterized 注意:之前的nose-parameterized已经更新为parameterized库了 模块下测试方法直接使用parameterized impo ...

  7. WGCLOUD如何监控数据库

    WGCLOUD默认是支持mysql,sqlserver,oracle,postgresql数据库监控,不用添加任何配置. DB2也是支持的,但是需要做一些小修改. 因为db2驱动包版本比较多,所以要自 ...

  8. React Hooks: use modal

    useModal: export const useModal = (initTitle: string, initContent: string | React.ReactElement) => ...

  9. Scala教程之:可扩展的scala

    文章目录 隐式类 限制条件 字符串插值 s 字符串插值器 f 插值器 raw 插值器 自定义插值器 Scala是扩展的,Scala提供了一种独特的语言机制来实现这种功能: 隐式类: 允许给已有的类型添 ...

  10. Docker虚拟化管理:30分钟教你学会用Docker

    关于Docker的官方介绍网上太多了我就不贴了,就实际体验来说Docker可以极大的简化环境搭建及服务部署的操作流程,大大降低部署的时间成本,解放你的双手. 本文不会深入讲解Docker底层架构及运行 ...