Question

In this code:

#include <iostream>

using std::cout;

class Foo {
    public:
        Foo(): egg(0) {}
        Foo(const Foo& other): egg(1) {}

        int egg;
};

Foo bar() {
    Foo baz;
    baz.egg = 3;
    return baz;
}

int main(void) {
    Foo spam(bar());
    cout << spam.egg;
    return 0;
}

the output is 3, while I expected it to be 1.

That means the copy constructor is not called in the line Foo spam(bar()).

I guess it's because the bar function doesn't return a reference.

Could you please explain what's really going on at the initialization of spam?

I apologize in advance if that's a dumb question.

Thanks!

Was it helpful?

Solution

Copy/move elision is the only allowed exception to the so-called "as-if" rule, which normally constrains the kinds of transformations (e.g. optimizations) that a compiler is allowed to perform on a program.

The rule is intended to allow compilers to perform any optimization they wish as long as the transformed program would work "as if" it was the original one. However, there is one important exception.

Per paragraph 12.8/31 of the C++11 Standard:

When certain criteria are met, an implementation is allowed to omit the copy/move construction of a class object, even if the constructor selected for the copy/move operation and/or the destructor for the object have side effects. [...] This elision of copy/move operations, called copy elision, is permitted in the following circumstances (which may be combined to eliminate multiple copies):

  • in a return statement in a function with a class return type, when the expression is the name of a non-volatile automatic object (other than a function or catch-clause parameter) with the same cv-unqualified type as the function return type, the copy/move operation can be omitted by constructing the automatic object directly into the function’s return value

[...]

  • when a temporary class object that has not been bound to a reference (12.2) would be copied/moved to a class object with the same cv-unqualified type, the copy/move operation can be omitted by constructing the temporary object directly into the target of the omitted copy/move

[...]

In other words, you should never rely on a copy constructor or move constructor being called or not being called in the cases for which the provisions of 12.8/31 apply.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top