Why isn't the copy constructor elided here?

c++, constructor, optimization

Solution

It is neither of the two legal cases of copy ctor elision described in 12.8/15:

Return value optimisation (where an automatic variable is returned from a function, and the copying of that automatic to the return value is elided by constructing the automatic directly in the return value) - nope. `f` is not an automatic variable.

Temporary initializer (where a temporary is copied to an object, and instead of constructing the temporary and copying it, the temporary value is constructed directly into the destination) - nope `f` is not a temporary either. `b.F()` is a temporary, but it isn't copied anywhere, it just has a data member accessed, so by the time you get out of `F()` there's nothing to elide.

Since neither of the legal cases of copy ctor elision apples, and the copying of `f` to the return value of `F()` affects the observable behaviour of the program, the standard forbids it to be elided. If you got replaced the printing with some non-observable activity, and examined the assembly, you might see that this copy constructor has been optimised away. But that would be under the "as-if" rule, not under the copy constructor elision rule.

Problem

(I'm using gcc with `-O2`.) This seems like a straightforward opportunity to elide the copy constructor, since there are no side-effects to accessing the value of a field in a `bar`'s copy of a `foo`; but the copy constructor is called, since I get the output `meep meep!`. ``` #include <iostream> struct foo { foo(): a(5) { } foo(const foo& f): a(f.a) { std::cout << "meep meep!\n"; } int a; }; struct bar { foo F() const { return f; } foo f; }; int main() { bar b; int a = b.F().a; return 0; } ```

Original source