Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Assigning result of function which returns a Foo to a const Foo&

Tags:

c++

I've got a function which returns an object of type Foo:

Foo getFoo();

I know the following will compile and will work, but why would I ever do it?

const Foo& myFoo = getFoo();

To me, the following is much more readable, and doesn't force me to remember that C++ allows me to assign an r-value to a const reference:

const Foo myFoo = getFoo();

What are the differences between the two? Why would I use the first over the second? Why would I use the second over the first?

like image 280
Dominic Rodger Avatar asked Jul 28 '09 20:07

Dominic Rodger


3 Answers

Contrary to popular opinion, there is no guarantee that assigning the result of a function returning an object by value to a const reference will result in fewer copies than assigning it to the object itself.

When you assign an rvalue to a const reference, the compiler may bind the reference in one of two ways. It may create a new temporary by copying the rvalue and bind the reference to that, or it may bind the reference directly to the rvalue itself.

If the compiler is not able to make the 'obvious' optimization to remove the temporary and elide the copy constructor for the return value of getFoo, then how likely is it to be able to do the more efficient form of binding an rvalue to a const reference without making a new temporary?

One reason to use a const reference would be to make the function more robust against potential slicing. If the return type were actually a type derived from Foo, then assigning to a base class const reference would be guaranteed not to slice, even if the compiler did make a temporary object from the rvalue returned by the function. The compiler will also generate the correct call to the derived class destructor whether or not the destructor in the base class is virtual or not. This is because the type of the temporary object created is based on the type of the expression being assigned and not on the type of the reference which is being initialized.

Note that the issue of how many copies of the return value are made is entirely separate from the return value optimization and the named return value optimization. These optimizations refer to eliminating the copy of either the rvalue result of evaluating a return expression or of a named local variable into the return value of a function in the body of the function itself. Obviously, in the best possible case, both a return value optimization can be made and the temporary for the return value can be eliminated resulting in no copies being performed on the returned object.

like image 68
CB Bailey Avatar answered Sep 22 '22 08:09

CB Bailey


I think GotW #88 answers this best

like image 40
Oleg Zhylin Avatar answered Sep 25 '22 08:09

Oleg Zhylin


It is valid to allow this sort of pattern:

void foo(const SomeType &);

foo(SomeType(bar))

In this case, a temporary SomeType is constructed and passed to foo. Most likely, the fact that you can also have constant references on the stack to temporaries is a side effect of the verbiage used to define this behavior in the standard. Note that, as onebyone mentioned in the comments, the temporary's lifetime is extended to be that of the reference itself.

like image 35
bdonlan Avatar answered Sep 22 '22 08:09

bdonlan