tl;dr
I want to call QString::number(int)
many times per second. It is very slow: seems like it allocates a new string each time. Tried to use setNum
on same string instead, still no joy.
Original, long question:
The problem
I have a big array of numbers (say, integers) and I want to format them into text, that will be then (maybe not immediately) written to file. Naive way looks approximately1 like this:
QString allData;
foreach(const int & value, values) {
allData += QString::number(value);
allData += '\n';
}
It takes about 280ms for 150000 integers on my machine which seems to much for me. I suppose that this is because QString::number
is called 150000 times and each time allocates new string. This is someway confirmed to be the root of the problem when I try to use itoa
(which does not allocate memory) instead.
Possible, but not-Qt [not-cute]
solution
QString allData;
char buffer[100]; // <-------
foreach(const int & value, values) {
_itoa_s(value, buffer, sizeof(buffer), 10); // <-------
allData += buffer;
allData += '\n';
}
This takes about 70ms for the same 150000 integers (about 4x faster) which is by now acceptable for me (I think I can do something with string concatenation as well, but let's leave this outside this question)
But I don't like that I have to use some unstandard, probably deprecated, probably unportable2 function (not to say that this just looks ugly).
Then I remembered that there is also an instance method: QString::setNum
. I hoped I could use the same pattern as with itoa
: have only one string allocated and modify it each time.
Desirable, but not working solution
QString allData;
QString number; // <-------
foreach(const int & value, values) {
number.setNum(value); // <-------
allData += number;
allData += '\n';
}
Unfortunately, this doesn't make big difference from QString::number
: again about 280ms, well, maybe 250ms but still too much.
So, congrats if you reached here :) and finally...
The Question(s)
- What would Qt experts advise me to do? Shut up and use
itoa
despite the distinct smell of C in otherwise fragrant C++/Qt code? - Or can I somehow say "C'mon, Qstring, just eat this number into you" ?
- I wonder why
setNum
did not do the trick?
Footnotes:
1 In actual code i have not just 150000 integers, but 50000 triples of integers which I also add '\t'
between them. This is the only difference from my actual code and I guess it is not important: here I'm interested only in performance of QString::number
vs itoa
.
2 Actually, I was surprised that MinGW also has _itoa_s
that behaves just like as Visual Studio's, but I still have some awkward feeling that using such a dirty function in my polished Qt code reduces its portability. Correct me if I'm wrong.
QByteArray
instead ofQString
(thanks to @SalvatoreAvanzo). As to your advice: I tried playing withreserve
, but it didn't have any impact. Seems like the implementation ofQString
'ssetNum
is just slower thanQByteArray
's one. Probably because QByteArray is just kinda wrapper overchar*
, whileQString
is much more complicated (encodings, etc). – SosQString::reserve()
prior to adding all those numbers? You know you'll need at least two characters per number, at most 10 (?), and you probably have a reasonable estimate how many digits you have on average. – ProsthesisQString::setNum
. – SosQString::resize()
(if necessary), then does the integer to text conversion, writing unicode characters directly to QString withmyqstr[index] = QChar(0x0030 + digitvalue);
would probably be fastest (U+0030 is Unicode code point for '0'). This is basically micro-optimization, but it allows taking shortcuts not possible in general purpose library code, and enables better optimizations (esp. inlining). – Canaveral