[Interest] Building strings with .arg() (arrrgh)
max-l at wdg.us
Tue Mar 3 07:16:49 CET 2020
Well, not sure if my question was too vague, TL;DR, or just no one
knows/cares to explain. So I created some benchmarks. Code and my
QStringLiteral().arg and .append() is consistently a little faster than
QString() versions, though certainly not by much. QLatin1String().arg()
and QStringView().arg() sit right about in between them (but are Qt
5.14+ only, and undocumented). The winner for raw speed is
QStringBuilder (string % string % ..., or the "+" equivalent with
QT_USE_QSTRINGBUILDER). For brevity it is certainly QString::asprintf()
especially if padding/formatting is needed.
Another thing I learned is that .arg(numeric_value) doesn't really ever
do better than .arg(QString::number()), especially when it can be
combined into one .arg() with other strings. Even if one wants to pad
the numbers, eg. QString::number(intVal, 16).rightJustified(4,
QChar('0')), it is still faster than the .arg() equivalent. Though
certainly more verbose.
Oh and QString.append(QLatin1String()) seems no faster than
append(QStringLiteral()), despite what the Qt docs seem to suggest. I
wasn't measuring memory usage per se, just overall speed.
If anyone sees any issues or naiveté with my benchmarks I'd love to hear
about it. I played with a lot of minor variations which didn't deserve
their own separate tests, but made some notes in the code comments.
Obviously there are almost limitless variations which I didn't cover,
and my focus was mainly on plain Latin1 strings.
On 2/16/2020 11:33 PM, Max Paperno wrote:
> HI folks,
> I'm confused about a "best" way to use .arg() with fixed/static strings
> (not tr()). Or if it should be used at all, for that matter, in terms of
> QStringLiteral seemed pretty good to me after reading several blog posts
> (from Marc Mutz, Kai Koehne, Olivier Goffart, among others), all of
> which are mentioned on Qtforum post [Create QString with QStringLiteral
> and arg] along with some opinions.
> Then found the [HEADS-UP: QStringLiteral] post by Marc on the
> development list and didn't feel so good about it anymore. Specifically
> where he says that using it with .arg() is an "anti-pattern" but not in
> any way that I can understand (vs. just using QString). I went through
> that whole meandering thread but didn't see string builder stuff brought
> up again.
> It also mentions (and I found other references) that QStringView and
> QLatin1String have .arg() methods, albeit w/out number formatting. Which
> I can see in the code, but aren't documented anywhere AFAICT. Nor can I
> find when these methods became available. I'm hesitant to use
> undocumented methods (though it wouldn't be the first time) and would
> prefer to maintain as much compatibility with older Qt versions as
> possible/reasonable. More importantly, I have no idea what doing
> something like QLatin1String("foo %1").arg(myQstring) would even mean.
> OTOH I found a number of code examples here and there (including KDE
> code, like Konsole) where people specifically changed
> QString("%1").arg() calls to use QStringLiteral instead.
> Also I'm not clear if using QStringLiteral with + (or %) operators is
> also an "anti-pattern"... I understand the methods like append() can
> make more efficient use of QLatin1String, but does a plain quote-wrapped
> char literal get implicitly converted to QString when used e.g. like:
> "Value of " + myQstring + " is: " + QString::number(x);
> Would it be more efficient to wrap those literals in a QStringLiteral,
> QLatin1String, QStringView (or u""), or just leave them bare?
> Realizing that "best" is subjective, and thinking of a specific project
> I'm working on, my goals, in order of importance, are, roughly:
> 1) Stability; 2) Minimal CPU time (fast, some of this could be used
> within animations and such); 3) Runtime memory use; 4) Clean code; 5)
> Size of produced binary.
> In many cases I'm just building strings for error/warning/status
> messages (but not QDebug streams, although they may end up as debug
> output eventually, or never be seen at all). And these don't, or
> shouldn't, happen very often at runtime. But in some cases the stings
> will be used internally by other code. In most (if not all) cases I
> don't care about UTF encoding, plain ASCII/L1 is fine. But there are
> often numerical types involved which need to be converted to strings
> somehow. And other strings to be inserted (with .arg()) are often
> QStrings (from Qt lib code or whatever). The built strings are typically
> passed on to other functions (as const QString &) for further processing
> or possible display to the user/downstream developer.
> What's a programmer to do? Does it even matter? Is there a faster way
> to build strings (within reason... yes I could just use C-level code but
> let's not get carried away).
More information about the Interest