Qt string builder in for loop
Asked Answered
B

3

11

following this and this documentation I would use the QStringBuilder in a for loop. The code where I should apply it is

QStringList words;
QString testString;

for (auto it = words.constBegin(); it != words.constEnd(); ++it)
{
    testString += "[" + *it + "] ";
}

However I don't understand how I could write it to use the QStringBuilder as here I'm doing an assignment, instead the QStringBuilder requires me to use the % operator and do only one assignment following the docs.

Budget answered 29/8, 2012 at 21:43 Comment(2)
I would use the join method in QStringList: testString = words.join(" ");Chrysolite
I would use it too but I must wrap each words inside bracketsBudget
A
7

AFAICS here, QStringBuilder doesn't have an operator %=.

However, if you want to maintain your loop, you could try something like this:

#include <QStringBuilder>
#include <QStringList>
#include <iostream>

using namespace std;

int main(int argc, char *argv[])
{
    QStringList words;
    words << "a1" << "a2" << "a3";
    QString testString;

    for (auto it = words.constBegin(); it != words.constEnd(); ++it)
    {
        testString = testString % *it % " ";
    }
    cout << testString.toStdString() << endl;
}

There's also mention of the QT_USE_QSTRINGBUILDER macro, which turns all + usage into %, provided that doesn't create problems elsewhere on your code.

EDIT:

In light of Marvin's comment, I believe I should add a few clarifications to my answer: This answer shows one way of explicitly using QStringBuilder and operator% in a loop. QStringBuilder was created to optimize concatenation expressions, and that optimization is achieved by eliminating the need for temporaries, and calculating the total size of the concatenated string and allocating it all at once (obviously, this can only be done at the "end" of the expression).

This means its optimal use is probably not in a loop (such as the code above). However, even then it gives you some sort of optimization, as can be seen both from the gprof and Measure-Command output for the two versions below.

Version 1 - QStringBuilder and operator% (gprof cumulative seconds: 0.46; PowerShell Measure-Command: 5:23s)

for (auto it = words.constBegin(); it != words.constEnd(); ++it)
{
    for (int i = 0; i < 100000; ++i)
    {
        testString = testString % *it % " ";
    }
}

Version 2 - Qstring and operator+ (gprof cumulative seconds: 0.61; PowerShell Measure-Command: 10:47s)

for (auto it = words.constBegin(); it != words.constEnd(); ++it)
{
    for (int i = 0; i < 100000; ++i)
    {
        testString = testString + *it + " ";
    }
}

So, I'd say that using QStringBuilder and operator% probably won't leave you noticeably worse (please note that the above values are a bit skewed, unless your app is actually performing thousands of concatenations with no I/O whatsoever). But, as usual, it's up to you to measure your execution times and decide what's working best for you.

Arithmomancy answered 29/8, 2012 at 22:4 Comment(5)
but would testString = testString % *it have the same benefits of using % like in the docs?Budget
@Stefano: I was actually considering that question this morning (must've been thinking about it in my sleep :D), and took a look at the sources. It won't give you any benefit, as QStringBuilder's operator% returns a new QStringBuilder. Stepping through my example, sure enough, it builds a QStringBuilder at every iteration, thus defeating its lazy evaluation mechanism. From what I could gather, this will only be useful when you have several concatenations on the same expression.Arithmomancy
:( the QStringBuilder is useless in this case. I would like to have a sort of string builder like the C# oneBudget
@Stefano: Yes. The difference between QStringBuilder and C#'s (and Java's) StringBuilder is that the former is not meant to be explicitly instantiated, and lacks the Append() functionality. OTOH, I suspect (hard to say without measuring) that your code is already as efficient as it gets. On your first Qt Docs link, code similar to yours, i.e., using operator+= is described like this: "Only one allocation and one copy, this is the optimum". Finally, if this loop isn't a bottleneck, I'd just leave it as it is.Arithmomancy
I don't think this works. QStringBuilder achieves its results by making the return value of operator% be QStringBuilder rather than QString. When QStringBuilder gets used in place of a QString, it's implicitly copied into a new QString. You're converting from QStringBuilder to QString in every loop iteration, so you lose the advantage of a real string builder.Rearm
A
3

I think that as long as you have the line

DEFINES *= QT_USE_QSTRINGBUILDER

in your .pro file, the compiler would use QStringBuilder for concatenating the strings. This will work in Qt 4.8 and up.

EDIT: the Qt docs say that this macro may make your project not source compatible. This article talks about how to work around that. Basically, you need to explicitly cast the result of the "+" expression to QString, e.g. use QString(s1 + s2) instead of just s1 + s2.

Aceldama answered 29/8, 2012 at 21:55 Comment(2)
I saw that macro but the docs also says it's source incompatible and suggests to use the % operatorBudget
@Stefano: this article: labs.qt.nokia.com/2011/06/13/… talks about how to work around that. It says that you need to explicitly cast the result of the "+" expression to QString, e.g. use QString(s1 + s2) instead of just s1 + s2.Aceldama
F
0

QString has a method reserve(), which allows reserving bigger portion of memory in ahead. This is useful in for example in loops when size of resulting string can be roughly estimated, as it can be used to avoid constant allocations due ever growing strings.

Fabiola answered 27/4, 2019 at 8:39 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.