You doubt how the return works

4

I have a question, I've been going around for a few days, and I can not understand how it works or what I'm doing wrong.

Starting point:

Suppose we have the following function:

 ArrayWrapper f(ArrayWrapper arr){
      return arr
 }

What my compiler does:

1- When passing through value, call the copy constructor, get arr , and return a temporary object arr .

2- We arrive at return , and as arr is temporary, and the function returns by value, because in this case it calls the constructor move and it returns my object.

Now my doubts come:

a) If it were my return : return ArrayWrapper(arr);

  • Compiler behavior:

    Call the copy constructor, get arr , and call the copy constructor again. ( ArrayWrapper(arr) , it's temporary or so I thought).

  • What I expected to be arr temporary, in ArrayWrapper(arr) the constructor would be called move returning a temporary object, and then the return when having to return a copy by value, call the move constructor again.

Why does the compiler call the constructor copy once it has already obtained arr , and does not call constructor move twice, once to get the temporary object ArrayWrapper(arr) and second to return it in return ?

    
asked by Jcpardo 25.05.2018 в 01:49
source

1 answer

2
  

Why does the compiler call the constructor copy once it has already obtained arr, and does not call constructor move twice, once to get the temporary object ArrayWrapper (arr) and the second to return it in the return?

arr can be as temporary as you want ... but the constructor move , to be called, needs a R-value and arr is an L-value .

To force the call to the move constructor you have to convert your L-value to an R-value and for that you can use std::move :

return ArrayWrapper(std::move(arr));

Now, in your first test:

return arr;

You have observed how the program ends up calling the constructor move directly, but did not we say that arr is an L-value ?

Indeed. arr is still an L-value but here other factors come into play:

  • arr is a local variable of the function
  • arr is not static
  • The instruction in question is a return

When these requirements are met (and there is the move constructor), an optimization that aims to reduce the overload of the return instructions comes into play. In this case it is understood that arr will not continue to exist after the return , so there is no problem in converting it implicitly in a R-value and thus call the constructor move .

The case that has led us to the question:

return ArrayWrapper(arr);

It does not fulfill these requirements because before the return an additional object of type ArrayWrapper is being created. An equivalent code would be:

ArrayWrapper temp(arr);
return temp;

Then, at the moment of creating temp , arr has not yet reached the end of its useful life (and it is not affected by the return ), then the copy constructor will be invoked since here it does not there are optimizations.

On the other hand, keep in mind that in C ++ there is another optimization referring to the return that is the omission of copy. This issue has already been addressed in StackOverflow, so in order not to repeat myself I refer you to this other question .

    
answered by 25.05.2018 в 07:54