Reputation: 2211
I have the following example and I am not sure I fully understand the move semantic logic:
#include <iostream>
#include <string>
#include <memory>
class Player
{
public:
Player(std::string name)
: m_name(std::move(name)) {}
private:
std::string m_name;
};
int main()
{
std::string s = "Zidane";
std::cout << s << std::endl;
Player player1(s); // not moved
std::cout << s << std::endl; // s = "Zidane"
Player player2(std::move(s)); // moved -> s is empty now
std::cout << s << std::endl;
return 0;
}
My explanation is that in the first case (Player1
), name
which is an lvalue of type std::string
is actually copied before the ctor of m_name
is called, then, the std::move
acts on the copy, so at the end the copy is empty and its content has been moved to m_name
using the move ctor. That's why the original argument s
remains untouched. Is it correct?
In the second case, it's not clear: std::move
converts the lvalue parameter into a reference rvalue and from there what happen ? In this case, the argument s is empty after the call.
Upvotes: 2
Views: 193
Reputation: 1907
A new std::string
is always created to 'populate' the name
argument, before Player(std::string name)
is called.
Overload resolution will dictate whether the copy ctor, or move ctor of std::string
will be called.
Player player1(s);
The new string is created by the copy ctor with signature basic_string( const basic_string& other );
, because 's' was an lvalue.
The total sum of operation that you pay is 1 move & 1 copy constructions of a string:
name
arg to the ctorm_name
class memberPlayer player2(std::move(s));
The new string is created by the move ctor for std::string
, with signature basic_string( basic_string&& other ) noexcept;
In the second case, you call std::move
, which casts s
into an rvalue reference. std::string
has 2 constructors, one which takes a const std::string&
, the other one takes a std::string&&
. An rvalue ref can bind to both an lvalue ref and an rvalue ref, but the rvalue ref version is a better match, so it will be selected.
The total sum of operation that you pay is 2 move constructions of a string:
name
arg to the ctorm_name
class memberPlease do note that, as pointed out by @aschepler and @underscore_d, the move ctor of std::string
does not need to clear the source string. One should not depend on this behavior, as it is not guaranteed and depends on how the move ctor for the strings are implemented.
Upvotes: 4