Let\'s say I have some function:
Foo GetFoo(..)
{
...
}
Assume that we neither know how this function is implemented nor the internals of
The semantic difference between const C& and const C in the considered case (when selecting the type for a variable) can affect your program in the cases listed below. They must be taken into account not only when writing new code, but also during subsequent maintenance, since certain changes to the source code may change where a variable definition belongs in this classification.
Cconst C& foo();
const C a = foo(); // (1)
const C& b = foo(); // (2)
(1) introduces an independent object (to an extent allowed by the copy semantics of the type C), whereas (2) creates an alias to another object and is subject to all changes happening to that object (including its end-of-life).
Cstruct D : C { ... };
const D& foo();
const C a = foo(); // (1)
const C& b = foo(); // (2)
(1) is a sliced version of what was returned from foo(). (2) is bound to the derived object and can enjoy the benefits of polymorphic behavior (if any), though at the risk of being bitten by aliasing problems.
Cstruct D : C { ... };
D foo();
const C a = foo(); // (1)
const C& b = foo(); // (2)
For (1), this is no different from the previous case. Regarding (2), there is no more aliasing! The constant reference is bound to the temporary of derived type, whose lifetime extends to the end of the enclosing scope, with the correct destructor (~D()) automatically being called. (2) can enjoy the benefits of polymorphism, but pays the price of the extra resources consumed by D compared to C.
struct B {
C c;
operator const C& () const { return c; }
};
const B foo();
const C a = foo(); // (1)
const C& b = foo(); // (2)
(1) makes its copy and goes on, while (2) is in trouble starting immediately from the next statement, since it aliases a sub-object of a dead object!