简体   繁体   中英

failed to understand c++primer about std::move()

The book C++ Primer says

It is essential to realize that the call to move promises that we do not intend to use rr1 again except to assign to it or to destroy it.

This is after the line:

int &&rr3 = std::move(rr1);

How to understand this sentence? Is there any change to rr1 after the call std::move(rr1) ?

Somebody thought this problem has be solved in What is std::move(), and when should it be used? But I don't agree that.The book written "We can destroy a moved-from object and can assign a new value to it, but we cannot use the value of a moved-from object."I don't know what it means that "we cannot use the value of a moved-from object.".Is there any code can explain it?

That particular code example misses the point. std::move doesn't do anything to the object that it's applied to. It's just a different format for a typecast, and its effect is to guide overload resolution in cases where it matters. For example:

void f(const my_type&);
void f(my_type&&);
my_type mm;
f(mm);            // calls f(const my_type&)
f(std::move(mm)); // calls f(my_type&&)

This matters because functions that take rvalue references (in this case, f(my_type&&) ) will typically do something nasty to their argument in order to make their work easier. For example, the copy constructor for std::vector makes a copy of the argument that's passed to it; the move constructor steals the argument's internal array, leaving the argument empty. So when you do std::vector<int> vec(std::move(other_vector)); you shouldn't do anything with other_vector except assign to it or destroy it, which is what the "rule" says.

The problem with the code example is that it doesn't do anything with the rvalue reference, so, as you've inferred, nothing in the object has changed, and you can continue to use it. But that's a silly use of std::move , and a pointless example.

move semantics can be understood satisfactorily when the objects have dynamically allocated memory inside them.

class MemoryBlock  
{
    public:
    MemoryBlock(size_t length) : _length(length), _data(new int[length])  
    {  
    }  

    // copy constructor.  
    MemoryBlock(const MemoryBlock& other) : _length(other._length), _data(new int[other._length])  
    {   
        std::copy(other._data, other._data + _length, _data);  
    }  

    // move copy constructor.  
    MemoryBlock(MemoryBlock&& other) : _data(nullptr), _length(0)  
    {  
        // Copy the data pointer and its length from the source object.  
        _data = other._data;  
        _length = other._length;  

        // Release the data pointer from the source object.
        other._data = nullptr;  
        other._length = 0;  
    }  

    // destructor.  
    ~MemoryBlock()  
    {  
        if (_data != nullptr)  
        {  
              delete[] _data;  
        }
        _length = 0;  
    }  

    private:  
    size_t _length; // The length of the resource.  
    int* _data; // The resource.  
};

// ok, 'a' has 20 byte memory inside it.
MemoryBlock a(20); 

// we are literally transferring the memory from 'a' to 'b' by using move copy constructor.
MemoryBlock b = std::move(a); 

// so you broke the promise: "that we do not intend to use object 'a' again" after it has been moved. 
// a::_data is now null and code will break.
MemoryBlock c = a; 

//when object 'a' will go out of scope it can be destroyed properly
//this will work because the promise holds: "that object can be destroyed" after it has been moved.

//this will work, since you are copying the memory inside of 'd' to 'a' using normal copy constructor.
//so you obeyed the promise: "that we can assign to object 'a'" after it has been moved.
MemoryBlock d(30); 
MemoryBlock a = d;

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