Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Best practice for const temporary types [closed]

Tags:

c++

c++14

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.

like image 919
bremen_matt Avatar asked Aug 16 '19 07:08

bremen_matt


2 Answers

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.

like image 155
lubgr Avatar answered Nov 17 '22 19:11

lubgr


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.

like image 6
463035818_is_not_a_number Avatar answered Nov 17 '22 21:11

463035818_is_not_a_number