zoukankan      html  css  js  c++  java
  • 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的创建。


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

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


  • 相关阅读:
    P2P学习(三)网络传输基本知识---TURN协议
    P2P学习(三)网络传输基本知识---STUN协议(二)
    P2P学习(三)网络传输基本知识---STUN协议(一)
    P2P学习(三)网络传输基本知识
    P2P学习(二)P2P中的NAT穿越(打洞)方案详解
    如何画UML时序图
    数据大屏、报表设计器等
    SQL Server查询指定表的操作记录
    ORACLE查询当前用户的权限
    InfluxDB:集群版使用指南(Influx-proxy)
  • 原文地址:https://www.cnblogs.com/codeForFamily/p/qt-creator-ide-source-learn-4-5.html
Copyright © 2011-2022 走看看