简体   繁体   中英

std::move inside move assignment operator

I read in another question that when implementing a move constructor it is good practice to std::move each member in the initializer list because if the member happens to be another object then that objects move constructor will be called. Like so...

//Move constructor
Car::Car(Car && obj)
    : 
    prBufferLength(std::move(obj.prBufferLength)), 
    prBuffer(std::move(obj.prBuffer)) 
{
    obj.prBuffer = nullptr;
    obj.prBufferLength = 0;
}

However in all the sample move assignment operators I've seen, there has been no mention of using std::move for the same reasons. If the member is an object then should std::move be used? Like so...

//Move assignment
Car Car::operator=(Car && obj)  
{
    delete[] prBuffer;

    prBufferLength = std::move(obj.prBufferLength);
    prBuffer = std::move(obj.prBuffer);

    obj.prBuffer = nullptr;
    obj.prBufferLength = 0;
    return *this;
}

UPDATE:

I appreciate there is no need to use std::move in the example I have chosen (poorly) however I'm interested in if the members were objects.

After reading the linked question, I can see the advice in the second most-upvoted answer is to use std::move in the initializer list for the move constructor because no matter if it is a primitive type or not, it will do the right thing. I somewhat disagree with that and think you should only call std::move where appropriate, but this is were personal preferences come in.

Also, for your move assignment operator, the way you have it is fine although I think the unnecessary call to std::move should be removed personally. Another option is to use std::swap which will do the right thing for you.

Car Car::operator=(Car && obj)  
{
    std::swap(this->prBufferLength, obj.prBufferLength);
    std::swap(this->prBuffer, obj.prBuffer); 
    return *this;
}

The difference between the above move assignment operator and your move assignment operator is that the deallocation of memory is delayed while your version deallocates the memory right away, this might be important in some situations.

It looks like prBuffer is a pointer and prBufferLength is some kind of integral type, so move isn't going to make any difference in this particular case as they are both fundamental types.

If prBuffer was a std::string for example, then you should use move to force the use of a move constructor or move assignment operator.

Like a lot of things in C++ and life there isn't a definitive yes or no answer to the question.

That said, as a general rule if incoming member will be cleared / reset / emptied and assigning the incoming member to the destination member will result in an assignment operator being called, then you will want to use std::move so that the move assignment operator will be called instead of the copy assignment operator.

If an assignment operator will not be called (ie just a shallow copy will be done) then using std::move is not necessary.

If your member objects would benefit from moving, you should certainly move them. Another strategy, which was demonstrated in the answer you linked to, is swapping. Swapping is like moving, but it's moving in both directions. If your class manages a resource, this has the effect of the object that was passed in (the rvalue) recieving the no longer wanted data. That data is then destroyed by that object's destructor. For example, your move assignment operator could be written like this:

Car Car::operator=(Car && obj)  
{
    // don't need this, it will be handled by obj's destructor
    // delete[] prBuffer; 

    using std::swap;
    swap(prBuffer, obj.prBuffer);
    swap(prBufferLength, obj.prBufferLength);

    return *this;
}

Also take a look at the Copy-and-Swap idiom. Which allows you to use the same assignment operator for both move and copy, but has the slight drawback that self-assignment results in an unnecessary copy.

I believe a (the?) better way to implement move assignment is to use the move constructor to create a new temporary object, and then swap it with the current object, just as with copy assignment.

It not only avoids code duplication but also prevents you from making mistakes accidentally by eg forgetting to move a member.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM