When we return a value from a C++ function copy-initialisation happens. Eg:
std::string hello() {
std::string x = "Hello world";
return x; // copy-init
}
Assume that RVO is disabled.
As per copy-init rule if x is a non-POD class type, then the copy constructor should be called. However for C++11 onward, I see move-constrtuctor being called. I could not find or understand the rules regarding this https://en.cppreference.com/w/cpp/language/copy_initialization. So my first question is -
What does the C++ standard say about move happening for copy-init when value is returned from function?
As an extension to the above question, I would also like to know in what cases move does not happen. I came up with the following case where copy-constructor is called instead of move:
std::string hello2(std::string& param) {
return param;
}
Finally, in some library code I saw that std::move was being explicitly used when returning (even if RVO or move should happen). Eg:
std::string hello3() {
std::string x = "Hello world";
return std::move(x);
}
- What is the advantage and disadvantage of explicitly using
std::movewhen returning?
You are confused by the fact that initialization via the move constructor is a special case of "copy initialization", and does not come as seperate concept. Check the notes on the cppreference page.
For returning a value from the function, check the description of returning on cppreference. It says in a box called "automatic move from local variables and parameters", where expression refers to what you return (warning: that quote is shortened! read the original for full details about other cases):
So in the special case of returning a local variable, the variable can be treated as r-value, even if normal syntactic rules would make it a l-value. The spirit of the rule is that after the return, you can't find out whether the value of the local variable has been destroyed during the copy-initialization of the returned value, so moving it does not do any damage.
Regarding your second question: It is considered bad style to use
std::movewhile returning, because moving will happen anyway, and it inhibits NRVO.Quoting the C++ core guidelines linked above:
So that library code you quote is suboptimal.
Also, you can not implicitly move from anything that is not local to the function (that is local variables and value parameters), because implicit moving may move from something that is still visible after the function returned. In the quote from cppreference, the important point is "a non-volatile object type". When you return
std::string& param, that is a variable with reference type.