struct Person
{
int mId;
std::string mName;
Person(int id, std::string name) : mId(id), mName(std::move(name))
{
}
};
struct Node
{
Person mData;
Node* mLeft;
Node* mRight;
Node(Person data) : mData(std::move(data)), mLeft(nullptr), mRight(nullptr)
{}
};
When writing a constructor for my Person class I intially defined my 'name' parameter to be a const reference but was recommended to change it to a simple value and use std move.
I understand this is because a rvalue string could be used to initialize 'Person', in which case the string would be moved into the variable 'name' as opposed to being copied. It would then be further moved into the member variable 'mName'- via std::move. I am also under the impression that this only works for std::string because it defines a move constructor.
What I don't understand is why I'm recommended to use std::move again in the 'Node' class constructor as I have not defined a move constructor for Person. Furthermore, I have noticed that removing the string member variable, mName, from the Person class stops this IDE reccomendation.
My guess is that this is because of the default move constructor of the Person class.
(In case it is helpful, my IDE is VS2022 and the reccomendation is from the extension Resharper')
CodePudding user response:
Your Person
class is following the "rule-of-zero", meaning it doesn't declare any copy/move operations or destructor explicitly.
That is usually the correct thing to do, because then the compiler will declare all of them implicitly and define them with the semantics you would usually expect from the these operations, if that is possible.
In your case, all members of Person
can be move-constructed, so the implicit move constructor of Person
will be defined to move-construct the members one-by-one.
This is what is used when you add std::move
in mData(std::move(data))
. Without it data
is a lvalue and instead the implicit copy constructor which copy-constructs each member would be used.
Copy-constructing a std::string
is often more costly than move-constructing it, which is probably why the tool warns about that case, but not if std::string
isn't there. Move-constructing and copy-constructing an int
member is exactly the same operation.
If you don't want to check each time what members a class has, you can simply always use std::move
in these situations. For example changing mId(id)
to mId(std::move(id))
is pointless, because id
is a scalar type, but it also doesn't make anything worse.