Qt Weekly #13: QStringLiteral

QStringLiteral is a macro that allows you to create QString objects from string literals with little to no runtime overhead. However, its usage can be tricky especially in code that must compile with different compilers, like the Qt code itself. This blog post lists some guidelines to help you avoid the pitfalls.

QString is the ubiquitous representation for a Unicode string in Qt. A common source for a QString are literals hard-coded into the application. In Qt 4, any such creation of a QString from a literal required creating the QString object on the heap, and then translating the literal characters from its run-time character codec to UTF-16. Since Qt 5.0, QStringLiteral allows to avoid this overhead by creating the object and doing the conversion at compile time.

Enable C++11 in your project

QStringLiteral is only optimized if the C++ compiler both supports lambdas and unicode literals. This is the case for Microsoft Visual Studio 2010 and newer, but GCC and Clang need to be told that they should support all C++11 features. When using qmake, this can be achieved by


CONFIG += c++11

Without the features, QStringLiteral falls back to QString::fromUtf8().

Use QStringLiteral only if a QString needs to be created

This sounds trivial, but it's not necessarily so. Some methods in the Qt API have overloads for either taking a QString, or a QLatin1String object. This is because Latin1 is simpler to parse than UTF-16, and therefore the QLatin1String version can be faster, and use less memory. This is worth remembering especially for some QString methods:


bool same = (str == QLatin1String("Hello"));
str.startsWith(QLatin1String("Hello"));
str += QLatin1String("World");

are more efficient than


bool same = (str == QStringLiteral("Hello"));
str.startsWith(QStringLiteral("Hello"));
str += QStringLiteral("World");

Do not use QStringLiteral for empty strings

Prefer


QString()

over


QStringLiteral("")

The default constructor for QString is cheaper in terms of both instructions and memory.

Avoid duplicated QStringLiterals

Avoid having multiple QStringLiterals with the same content. For plain literals and QLatin1String, compilers try to consolidate identical literals so that they are not duplicated. For QStringLiteral, identical strings cannot be merged.

String concatenation

Unfortunately Visual Studio does not implement concatenation for string literals in the way the C++11 standard says. That is, having multiple adjacent " " sections (e.g. useful to spread across multiple lines) won't work:


// error C2308: concatenating mismatched strings
// Concatenating wide "Hello" with narrow "World"
QStringLiteral("Hello " "World");

Other Visual Studio bugs

There are also other bugs in older Visual Studio versions. Here are a few known ones:


// (Visual Studio 2010, 2012)
// error: C1001: An internal error has occurred in the compiler.
QString array[2] = { QStringLiteral("Hello"), QStringLiteral("World") };


// (Visual Studio 2010)
// C2587: 'holder' : illegal use of local variable as default parameter
static QString formattedAddress(const QString &address,
        const QString &newLine = QStringLiteral(""))
{
  // ...
}

Summary

QStringLiteral speeds up the creation of QStrings from literals, at the expense of bigger binary sizes. To make these optimizations it requires C++11 features. There are cases though where using QStringLiteral does not pay off: For Qt API that optionally takes a QLatin1String, and for empty strings.

If you use QStringLiteral you should avoid declaring the same literal in multiple places: This furthermore blows up the binary sizes. Also, QStringLiteral exposes some bugs in Visual Studio compilers.

Further reading

Olivier Goffart explains both the reasons and the implementation of QStringLiteral in his highly recommended QStringLiteral blog post. Thiago Macieira blogged about it too.


Blog Topics:

Comments