Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is returning with `std::move` sensible in the case of multiple return statements?

Tags:

I'm aware that it's normally not a good idea to return with std::move, i.e.

bigObject foo() { bigObject result; /*...*/ return std::move(result); } 

instead of simply

bigObject foo() { bigObject result; /*...*/ return result; } 

because it gets in the way of return value optimization. But what in the case of a function with multiple different returns, particularly something like

class bar {   bigObject fixed_ret;   bool use_fixed_ret;   void prepare_object(bigObject&);  public:   bigObject foo() {     if(use_fixed_ret)       return fixed_ret;      else{       bigObject result;       prepare_object(result);       return result;     }   } }; 

I think normal return value optimization is impossible in such a function, so would it be a good idea to put in

      return std::move(result); 

here, or should I rather do (IMO uglier, but that's debatable)

  bigObject foo() {     bigObject result;     if(use_fixed_ret)       result = fixed_ret;      else{       prepare_object(result);     }     return result;   } 
like image 835
leftaroundabout Avatar asked Mar 02 '12 11:03

leftaroundabout


People also ask

Should I return std :: move?

std::move is totally unnecessary when returning from a function, and really gets into the realm of you -- the programmer -- trying to babysit things that you should leave to the compiler.

When should you use std :: move?

std::move is used to indicate that an object t may be "moved from", i.e. allowing the efficient transfer of resources from t to another object.

Can you have multiple return statements in a function C++?

You can have multiple return statements and it should not matter, if you are returning the same variable. However if you have multiple variables in your function and you return then differently depending on the code flow the compiler cannot perform such optimisation.

Where is std :: move defined?

In C++11, std::move is a standard library function that casts (using static_cast) its argument into an r-value reference, so that move semantics can be invoked. Thus, we can use std::move to cast an l-value into a type that will prefer being moved over being copied. std::move is defined in the utility header.


1 Answers

For local variables, there's no need to std::move them in the return statement most of the time, since the language actually demands that this happens automatically:

§12.8 [class.copy] p32

When the criteria for elision of a copy operation are met or would be met save for the fact that the source object is a function parameter, and the object to be copied is designated by an lvalue, overload resolution to select the constructor for the copy is first performed as if the object were designated by an rvalue. If overload resolution fails, or if the type of the first parameter of the selected constructor is not an rvalue reference to the object’s type (possibly cv-qualified), overload resolution is performed again, considering the object as an lvalue. [ Note: This two-stage overload resolution must be performed regardless of whether copy elision will occur. It determines the constructor to be called if elision is not performed, and the selected constructor must be accessible even if the call is elided. —end note ]


† Copy elision is very restricted in where it can be applied (§12.8/31). One such restriction is that the type of the source object has to be the same as the cv-unqualified return type of the function when dealing with a return-statement. It's also not applicable for subobjects of local variables that are about to go out of scope.

like image 51
Xeo Avatar answered Sep 21 '22 14:09

Xeo