I have a simple snippet:
class Object
{
private:
int value;
public:
Object(int value) : value(value) { cout << "Object::ctor\n"; }
Object(const Object& obj) { cout << "Object::copy-ctor\n"; }
Object(Object&& obj) { cout << "Object::move-ctor\n"; }
};
Object take_and_return_obj(Object o) { return o; }
int main()
{
Object o(5);
take_and_return_obj(o);
}
Now, this, as expected, prints a copy
and move
constructor.
Object::copy-ctor
Object::move-ctor
This is because o
gets copied into the function using the copy-ctor, and then gets sent back using the move-ctor since the function is over and the return value is an xvalue.
However, something happens when the initial argument to the function is also an xvalue:
int main()
{
Object o = take_and_return_obj(Object(5));
}
What happens is that somehow nothing happens when the value is sent to the function:
Object::ctor
Object::move-ctor
I assume that the move
is for the return operation, so that is not affected by this change. However there is no copy-ctor called to create the o inside the function's scope. I know its not any kind of pointer or reference since I made the function take the argument by value.
So my question is: what exactly happens to the xvalue I create in main
so that the argument inside the function gets its value?
This is more of an educational question, so do not be afraid to go into more in-depth answers.
CodePudding user response:
Yes, in take_and_return_obj(Object(5));
, the copy/move operation for constructing parameter o
is elided; which is guaranteed since C 17.
Under the following circumstances, the compilers are required to omit the copy and move construction of class objects, even if the copy/move constructor and the destructor have observable side-effects. The objects are constructed directly into the storage where they would otherwise be copied/moved to. The copy/move constructors need not be present or accessible:
...
... In the initialization of an object, when the initializer expression is a prvalue of the same class type (ignoring cv-qualification) as the variable type:
T x = T(T(f())); // only one call to default constructor of T, to initialize x
CodePudding user response:
This answer is for those who do not know the term copy-elision.
The question is answered by this answer (including the 2 linked answers).
In certain cases the compiler may omit copying things. Such cases include scenarios like taking or returning xvalues from functions. In these cases the copy/move ctors will not be called so that no extra copies of the object are created.