Qt (C++) - method argument optimization?
-
@jsulm said:
No need to use references for basic types.
dangerous advice for a C++ beginner.
Imagine a list with a few hundrets of thousands int values contained. All values need to be traversed and copied in memory. And this is sub-optimal when it can be avoided.I forgot to mention that many classes are implicitly shared in Qt. So like the QList for example.
Nevertheless the const-reference way is the recommended one in all cases. -
@raven-worx I was talking about basic types like int, double, char and so on not about complex types like lists.
-
ah k...got it after reading it a second time
-
Thanks for the tips guys,
I will revisit my code and change to "const reference" where I don't modify the argument and the argument is something else than a basic type (int, double).
I think jsulm meant basic type that are not in container, e.g (int and not QList<int>)
Also what I meant for the compiler is to detect wheter we change the argument, if so, pass it by value. If not, pass it by reference. But of course C++ let you modify function argument, and this would not let you do that (not a bad thing IMO..) -
Let say I have a constructor with a "const QVector<int>& vecId"
My goal is that I can manipulate this list but not modify it. (read only).So I assign this list to a local QList of this Object.
this.vecId = vecId; // vecId is of type QVector<int> vecId2 qDebug() << "THIS IS THE LENGTH BEFORE REMOVAL " << this->vecId .size(); this->vecId .removeAt(0); qDebug() << "THIS IS THE LENGTH AFTER REMOVAL " << this->vecId .size();
Here I can still modify the QList
Is there a way to optimize this code or am I forced to pass the whole list by value like I was doing before? ThanksInteresting, maybe I don't need to do it
-
@maximus said:
I wonder why the compiler doesn't do this stuff for us, detect if we modify the method argument and optimize accordingly
Because it can't. You can pass that parameter into another function. It can get an address of it and modify that. It can const_cast the parameter. It can use a goto into a code that modifies it. It can do million other crazy stuff with it. Compiler can't make guesses. It simply needs to be perfectly deterministic. The only way this sort of automatic optimization was possible is if your whole program was a constexpr evaluated at compile time, but then there would be no point in optimizing it at all, and such program would be useless anyway.
Here I can still modify the QList
No. You can (and did) modify a copy of the list. The original is intact.
Interesting, maybe I don't need to do it
Implicit sharing is meant to help moving large structures around but it's not free! It is still a copy of the object. A copy constructor is called. An internal reference count is changed as an atomic operation. The data is not copied (initially) but still a lot is going on. A const reference is basically a pointer on the stack, or even in a cpu register, which is as close to "free" as you will get.
-
I was thinking something like this method
void printString(QString s) { qDebug() << s; /* The compiler could detect that nothing was assigned to "s" since it can read the whole function, so it replace the argument with const QString& s. In other words, the value of "s" after function execution is the same value as before for any input possible. */ }
I will read more on C++. For now, I will only replace my getter functions and add const at the end of them. Hopefully I can get the benefit on implicit sharing without doing too much work.
I just find it a bit sad the learning curve of C++ compared with other languages. That's what you get for starting with an "easy" language that doesn't have pointers and do memory management for you I guess. Thanks! -
I was thinking something like this method
You're forgetting that in c++ you can overload operators.
The signature of<<
isQDebug & operator<<(const QString & s)
and that to some extent helps.
But what if it wasQDebug & operator<<(QString& s)
? How would the compiler know then thatoperator<<
does not modifys
internally?I said to some extent because the compiler is really fighting an uphill battle.
For example the first line in that operator method could be something likeQString& foo = const_cast<QString&>(s); foo = "gotcha!";
If you think a compiler can follow this then what if the implementation was in a different translation unit or even in a different library? Of course the example is contrived and plain silly, but none the less valid c++ that a compiler must deal with correctly and not optimize stuff away.
-
Thanks Kawa, that example made me understood the whole problem.
Since any method can modify it's argument in C++, we need to had const to explicitly state that it does not.
I just never use this C++ feature (passing by reference without const), so that's probably why it was not natural for me.
I will go back to the books! I just feel changing an argument is "wrong" and I use a return value to do it, old habits... -
@maximus said:
I just feel changing an argument is "wrong" and I use a return value to do it, old habits
If possible you should definitely avoid non-const reference arguments. Returning a value instead of modifying an argument is actually a very good thing in many situations. The optimizer will like that a lot.
Since you're up to reading about c++ you might want to look up return value optimization.
The fastest way to copy is to avoid copying in the first place ;)Happy coding.