关于QString、QLatin1String、QStringLiteral

编码过程中,会不可避免地涉及到字面字符串,很多时候大家都是直接使用,没有太多考虑转换和效率的问题。

如果调用的函数支持const char*这样的参数,那么直接使用字面字符串没有问题,这种函数一般都是极为常用的函数才会提供const char*这样的重载,比如QString的operator==、operator+等等。

如果存在接受QLatin1String的参数,那么就可以提供QLatin1String("xxx")这样的参数,因为QLatin1String基本上就是const char*的一层薄薄的封装,所以这样做的效率也是挺高的。

但是,在只接受QString参数的函数,无论我们给一个字面字符串或QLatin1String,都会隐式构造一个临时的QString对象,构造这个对象需要在栈上申请一定的内存空间,然后把字符串拷贝过去,如果这样的调用比较多,那还是一笔不小的开销。此时,我们可以使用QStringLiteral来减少这个开销。
QStringLiteral其实是一个宏,展开来就是一个lambda函数的调用,该lambda函数内部使用了一个只读的静态变量保存了QString对象内存布局的POD对象,让这份数据保存在了程序的.rodata段。
当代码运行到这的时候,实质就是对该lambda函数的调用,该函数返回了一个用上面所说的POD对象构造出来的QString对象,因为QString是隐式共享的,所以这里并没有发生前面所说的开销,就可以提高效率。
这里用下面的代码展示QStringLiteral展开来之后的样子,理解起来会更加容易:

o->setObjectName(QStringLiteral("MyObject"));
// 展开之后:
o->setObjectName(([]() {
        // 计算字面字符串的大小,减去1个null字符
        enum { Size = sizeof(u"MyObject")/2 - 1 };
 
        // 编译期就完成了这个初始化
        static const QStaticStringData qstring_literal =
        { { /* ref = */ -1,
            /* size = */ Size,
            /* alloc = */ 0,
            /* capacityReserved = */ 0,
            /* offset = */ sizeof(QStringData) },
          u"MyObject" };
 
         QStringDataPtr holder = { &qstring_literal.str };
         QString s(holder); // 调用QString(QStringDataPtr&)构造函数
         return s;
    }()) // 调用lambda函数
  );

总结:
1、支持const char*或者QLatin1String的地方使用对应的参数
2、需要QString的地方,如果该QString不会修改的话,那使用QStringLiteral
3、需要QString且该QString可能会被修改的话,还是直接使用QString或者隐式转换吧

你可能感兴趣的:(关于QString、QLatin1String、QStringLiteral)