Suppose I am doing a computation that involves creating a temporary object that I won't modify:
auto tmp = val * val;
// Do some calculations with tmp...
Further, I do not need tmp
to be an lvalue since I won't be taking its address.
Under these conditions, which idiom should I be using in my code:
1. auto tmp = val * val;
2. const auto tmp = val * val;
3. const auto & tmp = val * val;
4. auto && tmp = val * val;
5. const auto && tmp = val * val;
Note that I am explicitly leaving off the auto &
because that will often lead to UB. However, I am aware that the const auto &
will extend the temp lifetime, so I leave that as an option here.
Unsurprinsgly, for this simple example, -O3
compiles down to the same code anyway: https://godbolt.org/z/oXj3hd
But in a more complicated example, I would imagine that they don't.
My thinking is that option 3 or 5 are probably the most correct since they will preserve the constness of the object, and because they will hold temporary objects.
EDIT:
A lot of people are mentioning the fact that in this simple example, there will not be a need to even name the temp. That is correct. What I am after is a recommendation for what to do when the expression generating the temp is complicated, and will be used repeatedly in the code.
auto tmp = val * val;
Use this when you want to cast tmp
to an rvalue later on (std::move(tmp)
).
const auto tmp = val * val;
Use this when you don't need to std::move(tmp)
afterwards. Clear, not surprising, honors Scott Meyers Item "Use const
whenever possible".
const auto & tmp = val * val;
Don't do this. It does lifetime extension, but you don't gain anything from that compared to 2., because the object has to live somewhere anyhow. When val*val
returns an object by value, you won't copy it with 2. due to (N)RVO (assuming that operator *
for val
objects behaves sanely), so const auto& tmp
and const auto tmp
will both refer to an object within the stack of your scope.
auto && tmp = val * val;
const auto && tmp = val * val;
Doesn't yield any performance benefits, but complicates reading of the code. Don't do it.
Why would you bind a reference to val * val
? Performance aside, I would consider this as obfuscation.
Unsurprinsgly, for this simple example, -O3 compiles down to the same code anyway:
Yes, no big surprise here. So just use the most concise and least contrived. const
is not for performance and the compiler is clever enough to realize that the variable isnt modified without your help, though const
documents the constness for you and thus adds to readability. Hence
const auto tmp = val * val;
Anything else is turning something simple into something unnecessarily complicated.
Last but not least, consider if you need the temporary at all, or if you can simply write val*val
in place of tmp
. On the other hand, if you use tmp
many times, it is of course worth to give it a meaningful name (meaningful = something more meaningful than tmp
;)
PS: Note that const
prevents moving from tmp
, which might be a downside on performance. However, in general when worried about performance you should first write readable code and only then measure for performance.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With