C ++ 11: Do semantics cross by pass by value?

I have an API that looks like this:

void WriteDefaultFileOutput(std::wostream &str, std::wstring target) { //Some code that modifies target before printing it and such... } 

I am wondering if it would be wise to incorporate the semantics of movement by doing the following:

 void WriteDefaultFileOutput(std::wostream &str, std::wstring&& target) { //As above } void WriteDefaultFileOutput(std::wostream &str, std::wstring const& target) { std::wstring tmp(target); WriteDefaultFileOutput(str, std::move(tmp)); } 

or is it just a template that the compiler should still figure out?

+7
source share
2 answers

"Pass by value" can mean either copying or moving; if the argument is lvalue, the copy constructor is called. If the argument is rvalue, the move constructor is called. You do not need to do anything special using rvalue references to get the semantics of movement with value-by-value passing.

I delved into this topic in What is the semantics of displacement?

+15
source

You should prefer passing by value if you are going to make a copy with immutable values. For example, your version of const& WriteDefaultFileOutput explicitly copies this parameter, and then moves the copy with the move version. This means that if WriteDefaultFileOutput is called with a movable value (xvalue or prvalue), then it will be moved, and if it calls with lvalue, it will be copied.

This means that there is no difference between the two forms of this function. Consider this:

 WriteDefaultFileOutput(L"SomeString"); 

In your first case, it will create a temporary wstring . Prvalues ​​are times, so it will be "moved" to the parameter (since wstring has a move constructor). Of course, any compiler that deserves its salt will override the course and simply build a temporary value directly in the parameter.

In your second case, more or less the same thing happens. A temporary wstring . Prvalues ​​are times, so they can bind to && types. Therefore, it will call the first version of your function using the r-value reference to a temporary one. The only possible difference would be from a compiler that cannot overcome the move. And even then, traffic is not so expensive (depending on your implementation of basic_string ).

Now consider the following:

 std::wstring myStr{L"SomeString"}; WriteDefaultFileOutput(myStr); 

In the first case, a call to WriteDefaultFileOutput will copy the value of myStr into the function parameter.

In the second case, myStr is the value of l. It cannot be attached to the && parameter. Therefore, the only version that he can name is the const& version. This function will manually create a copy, and then move the copy from another.

Identical effect. Your first version has less code, so for obvious reasons.

In general, I would say that there are only two reasons to accept the parameter as && :

  • You are writing a move constructor.
  • You are writing a forwarding function and should use perfect forwarding.

In all other cases, when you want movement to be possible, just take the meaning. If the user wants to copy, let them be copied. I believe that if you want to explicitly prohibit copying a parameter, you can take && . But the main problem is clarity.

If you take a value parameter and the user provides a roaming value, then the value provided by the user will always be roaming. For example, your version of && WriteDefaultFileOutput should not actually move data from its parameter. It certainly can. But this is optional. If he accepted the value, then he would already have declared the data.

Therefore, if a function takes a parameter of a value, and you see std::move at that value, then you know that the moved object is now empty. It is guaranteed to be ported from.

+2
source

All Articles