Home > Software engineering >  IDE recommends 'pass by value and use std move' when parameter class has no move construct
IDE recommends 'pass by value and use std move' when parameter class has no move construct

Time:02-20

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.

  • Related