Home > Net >  How does C "send" temporary values to functions by value?
How does C "send" temporary values to functions by value?

Time:10-04

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.

  •  Tags:  
  • c
  • Related