QStringLiteral、QLatin1String作用及性能总结

目录

1.QStringLiteral

2.QLatin1String

3.性能验证

4. 总结


1.QStringLiteral

     这是一个宏定义,定义如下:

QStringLiteral(str)

       该宏为字符串字面量在编译时期产生一个QString对象。产生的字符串数据存放在编译对象文件的只读片区。如果你写代码像下面那样:

 // hasAttribute函数接受一个类型为QString的参数
  if (node.hasAttribute("http-contents-length")) //...

       上面代码将会产生一个QString的临时对象,该临时对象作为参数传递给hasAttribute函数。这是非常昂贵的、效率非常低的操作。因为它涉及到内存分配、拷贝、转换字符串字面常量数据到QString内部编码等工作。通过QStringLiteral可以避免这种高代价操作。将上面代码改为如下:

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

        在这种情况下,QString内部数据将会在编译时期产生,而不是在每次运行时进行字符字面常量内存分配、字符字面量向QString对象的转换。

        用QStringLiteral代替用双引号括起来的普通C++字符串字面常量,能够明显地提高从字符串字面常量创建QString对象实例的效率,且创建QString对象实例是在编译时进行的

        注意:当函数重载了QLatin1String参数时,调用重载QLatin1String类型的函数比QStringLiteral高效,因为它避免了转为QString,例如: 在Qt 5.14.1版本中,QString::operator==的重载函数共有如下三个:

bool operator==(QLatin1String other) const
bool operator==(const char *other) const
bool operator==(const QByteArray &other) const

 其中第1个能直接比较QLatin1String,如下:

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

的效率比如下代码效率高: 

if (attribute.name() == QStringLiteral("http-contents-length"))

2.QLatin1String

        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对象,也不需对字符数据深度复制。

        如果不想让应用程序访问、调用QString类中参数为const char*的系列函数,可以使用QT_NO_CAST_FROM_ASCII宏禁止C字符串字面量自动转为unicode编码的QString字符串。为了提供一种高效率地指定常量Latin-1编码的字符串方式,Qt提供QLatin1String类,该类是对const char*的一层轻量封装。上面的代码用QLatin1String改写为如下:

  if (str == QLatin1String("auto")
          || str == QLatin1String("extern")
          || str == QLatin1String("static")
          || str == QLatin1String("register") {
      ...
  }

从类型来说,这有点长,但是它提供了和前文第1个版本同样的优点,且当转为Latin-1 编码时,比QString::fromLatin1()执行快。

        多亏了以QLatin1String参数的QString的构造函数!在需要用QString的地方都可以QLatin1String,例如:

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

注意:如果用QLatin1String作为实参传给被调用函数,而被调用函数实际没有重载QLatin1String参数,即该函数的形参不是QLatin1String类型,这将导致隐式类型转换到QString,从而触发内存分配,这通常是我们想避免的,在这种情况下,用QStringLiteral替代QLatin1String是不错的选项。   也就是说如下函数:

void fun(const QString& str)
{
   // 其它代码
}

应优先采用

fun(QStringLiteral("csdn");

而不是采用

fun(QLatin1String("csdn");

而如果fun函数像如下那样:

void fun(const QLatin1String& str)
{
   // 其它代码
}

应优先采用:

fun(QLatin1String("csdn");

3.性能验证

 如下程序,验证了QLatin1Literal和QStringLiteral在效率上的区别:

#include <QtCore/QCoreApplication>
#include <QElapsedTimer> 
#include<QDebug>

void testQStringLiteral(const QString&str)
{
    //qDebug() << "QString" << str;
}

void testQStringLatin1(const QLatin1Literal& str)
{
   // qDebug() << str;
}

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    const auto nLoopTimes = 1E7;

    QElapsedTimer t;
    t.start();
    for (auto i = 0; i < nLoopTimes; ++i)
    {
        testQStringLiteral("Literal");
    }

    qDebug() << "Literal:" << t.elapsed();

    QElapsedTimer t1;
    t1.start();
    for (auto i = 0; i < nLoopTimes; ++i)
    {
        testQStringLiteral(QStringLiteral("Literal"));
    }

    qDebug() << "QStringLiteral:" << t1.elapsed();

    QElapsedTimer t2;
    t2.start();
    for (auto i = 0; i < nLoopTimes; ++i)
    {
        testQStringLatin1(QLatin1Literal("Literal"));
    }

    qDebug() << "QLatin1Literal:" << t2.elapsed();

    return a.exec();
}

上面代码用字符串字面量、 QStringLiteral宏、QLatin1String分别调用函数1E7次,在我本机耗费时间如下:

通过运行结果,可以看到:直接传递字符串字面量达到了惊人的7876ms;而采用QStringLiteral宏,只需760ms,而采用QLatin1String仅仅只需52ms。

4. 总结

  • 当被调用函数参数是QString类型时,利用QStringLiteral宏传字符串比直接传字符串效率高。
  • 当被调用函数存在有QString类型又存在QLatin1String类型的重载函数时,利用QLatin1String向函数传字符串比利用QStringLiteral宏向函数传字符串效率高。
  • 当被调用函数参数仅仅存在QString类型,而不存在QLatin1String类型的重载函数时,利用QStringLiteral宏传字符串比利用QLatin1String向函数传字符串效率高。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值