Can compilers automatically apply move semantics in the setter method?

I want to know if the compiler is allowed to automatically use the move constructor for wstring in the following setter method (without calling std :: move explicitly):

void SetString(std::wstring str) { m_str = str; // Will str be moved into m_str automatically or is std::move(str) needed? } 

From what I read, it sounds like the compiler is not allowed to make this decision, since str is an lvalue, but it seems obvious that using move here would not change the behavior of the program.

Ban on moving, will some other type of copy be applied?

+4
source share
3 answers

[is] the compiler [...] allowed to automatically use the move constructor

Yes, it would be nice. But this is not only optimization, but also a real impact on the language.

Consider the type of movement only of type unique_ptr :

 std::unique_ptr<int> f() { std::unique_ptr<int> up; return up; // this is ok although unique_ptr is non-copyable. } 

Suppose your rule is included in the C ++ standard, called the "last occurrence argument" rule.

 void SetString(std::unique_ptr<int> data) { m_data = data; // this must be ok because this is "argument last occurence" } 

Checking the correct use of the identifier in the return. Checking if this is the "last argument event" is not.

 void SetString(std::unique_ptr<int> data) { if (condition) { m_data = data; // this is argument last occurence } else { data.foo(); m_data = data; // this is argument last occurence too } // many lines of code without access to data } 

This is also valid code. Thus, each compiler will have to check the "last occurrence argument", which is not easy. To do this, he would have to scan the entire function to decide if the first line is valid. It's also hard to talk about a person if you need to scroll 2 pages down to check it out.

No, the compiler is not allowed in C ++ 11. And it probably will not be allowed in future standards, because this function is very difficult to implement in compilers in general, and it's just a convenience for the user.

+3
source

no, the move semantics will not be used here, since str can be used in the following code, in fact, even if it was an rvalue, you would still need std :: move force it .. if you want to use the move semantics i will advise getting wstring && str for the function, and then using move ..

+1
source

No, the compiler is not allowed. For some reason, not only because it is difficult to do. I think copying and moving can have side effects, and you need to know when you can expect each one to be used. For example, it is well known that returning a local object will move it - you expect it to be documented, this is normal.

So, we have the following features:

Your example:

 void SetString(std::wstring str) { m_str = str; } 

For r-values: one r-ref in str , plus a copy in m_str . For l-values: copy to str copy to m_str .

We can do this “better” manually:

 void SetString( std::wstring str) { m_str = std::move(str); } 

For r-values: one r-ref in str , plus a transition in m_str . For l-values: copy in str a move to m_str .

If for some reason (you want it to compile without C ++ 11 without changes, but automatically take advantage of C ++ 11 when porting the code?), You don’t want to “manually optimize” the code you can do:

 void SetString(const std::wstring& str) { m_str = str; } 

For r-values: one ref in str , plus a copy in m_str . For l-values: a ref in str a copy in m_str . Never copy.

+1
source

All Articles