Using QString Effectively
This article may require cleanup to meet the Qt Wiki's quality standards. Reason: Auto-imported from ExpressionEngine. Please improve this article if you can. Remove the {{cleanup}} tag and add this page to Updated pages list after it's clean. |
Written By : Girish Ramakrishnan, ForwardBias Technologies
This page explains the purpose of various QString related classes.
Creating a QString from a C-string may involve a malloc. For example, there is possibly a hidden-malloc cost in the following code.
if (fruit == "apple") { … } // possibly hidden malloc
QString provides a QString::operator==(const char *) overload for comparison with C-strings. As explained in QtString, the encoding of C-strings is determined using QTextCodec::setCodecForCStrings(). When no special encoding is set, Qt performs the above comparison by providing a specialized function that compares a Unicode string (fruit) and the Latin-1 string ('apple'). This comparison is fast and requires no mallocs.
However, when QTextCodec::setCodecForCString is set, "apple" gets converted into a QString using QString::fromAscii(). This means that QString will allocate memory for the string "apple" and creates a deep copy of the C-style string before performing the comparison!
Application developers set QTextCodec::setCodecForCString() in main() without realizing that this has the side-effect of a malloc for every single C-style string comparison.
Since comparisons with Latin-1 C-strings are very common in programs, Qt provides a special class called QLatin1String that just holds a pointer to a Latin-1 encoded C-string. In addition, QString provides a QString::operator(const QLatin1String &) overload that calls the specialized function that compares the Unicode string and Latin1-string. We can make the above code assuredly fast by writing it instead as,
if (fruit QLatin1String("apple")) { … } // fast and mentions encoding
In Qt's own code, all C-strings comparisons use QLatin1String since the application can choose an arbitrary codec for C-strings.
QStringRef : String manipulation without the malloc
QString has various methods for string manipulations like mid(), left(), right(). All of them create a new QString and hence a malloc/deep copy of data in an existing QString. Instead, QString::midRef(), QString::leftRef() and QString::rightRef() can be used to obtain a QStringRef. A QStringRef is a reference of a portion of a QString. QString also provides many overloads like QString::operator==(const QStringRef &) for optimal use with QStringRef.
QString::reserve and QString::squeeze
It's better to call QString::reserve to allocate extra memory in advance so that every call to QString::append() does not result in a malloc. Extra memory can be reclaimed using QString::squeeze.
QStringBuilder : Fast QString concatenation
The code below requires atleast 2 mallocs. First a malloc to store the result of "(" + type. And then another malloc for appending the ")". The number of mallocs increases with each addition of "" operator.
if (foo.startsWith("("'' type + ")"))
The additional mallocs can be avoided if the length of the final QString is known in advance. Qt 4.6 introduces an internal class called QStringBuilder that "reserves" memory for a concatenation chain in a single shot. It does so by having each of the + operations above return a different class (not QString anymore). This class keeps track of the string's that are being appended and the required memory at each step. At the final step, when the concatenation operation gets converted into a QString it allocates memory in a single shot and copies all the strings in the chain one after another. This feature can be enabled by including <QtCore/QStringBuilder>. and using use the operator instead of ''. One would now write,
if (foo.startsWith("(" % type % ")"))
'' can be used instead of by defining QT_USE_QSTRINGBUILDER. See Fast concatenation for more details