1

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?

hitwlh
  • 71
  • 9
  • Possible duplicate of [What is std::move(), and when should it be used?](http://stackoverflow.com/questions/3413470/what-is-stdmove-and-when-should-it-be-used) –  May 06 '16 at 08:59
  • `std::move` itself doesn't change the object. It changes it's *type*, such that the assignment may change `rr1`. (Although in this case, it won't). Since the assignment can change the value of `rr1`, you can't rely on it afterwards. – BoBTFish May 06 '16 at 08:59
  • *Is there any change to rr1 after the call std::move(rr1)?*. Well, yes. Sometimes. That's kinda the point. If you move stuff *from* a *to* b, normally both a and b change. In the C++ case a *may* change, or may not. – n. m. could be an AI May 06 '16 at 09:00
  • @BoBTFish: I wouldn't say that anything changes "an object's type". C++ s statically typed, and an object's type is fixed throughout a program. – Kerrek SB May 06 '16 at 09:00
  • @KerrekSB `auto` *chuckles* but seriously, @OP: http://en.cppreference.com/w/cpp/utility/move , http://www.cplusplus.com/reference/utility/move/ –  May 06 '16 at 09:01
  • @KerrekSB Sure. But I'm not really sure how to explain it properly in one sentence, or even if that is worth doing. A reasonable "model"(/lie) may be good enough here. – BoBTFish May 06 '16 at 09:01
  • 2
    Well, the point of this promise is that you don't even ask such a question. The object `rr1` is no longer meant to be scrutinized after you have moved from it. It may be unchanged, or it may have a completely unrelated or unpredictable value, but you promised that you weren't going to care when you requested to move from it. – Kerrek SB May 06 '16 at 09:02
  • 3
    @BoBTFish: Hm. I try not to lie when explaining C++; it's hard enough to take many of the non-lies seriously in this most horrendous language... – Kerrek SB May 06 '16 at 09:03
  • Thanks for the quick reply.I see there may or may not changes.But how to change ? Can somebody write some codes to expalin this?Thank you very much. – hitwlh May 06 '16 at 09:17
  • not sure what you mean with some code, I am also not too familiar with moving, but I guess, that would explain it a bit : `int &&rr3 = std::move(rr1);` after this you shouldnt use the value, ie dont do anything like `int rr4 = rr1;` because you shouldnt use the value of `rr1` anymore – 463035818_is_not_an_ai May 06 '16 at 09:26
  • But in this example, if I use int rr4=rr1; there aren't any problems.So I am doubting that in which case three will be problems when using code like int rr4=rr1 – hitwlh May 06 '16 at 09:28
  • what do you mean with no problems? after you moved the value from `rr1` to somewhere else, it does not make sense to do `rr4=rr1` afaik – 463035818_is_not_an_ai May 06 '16 at 09:29
  • int tp = 4; int& sd1 = tp; int&& sd2 = std::move(sd1); cout << sd2 << endl; cout << sd1 << endl; cout << tp << endl; tp = sd1; cout << tp << endl;In this case,all the cout result is right?even if I use sd1 to assign tp. – hitwlh May 06 '16 at 09:31
  • you cannot use one code example to find out if something is ok, there is undefined behaviour and even without that, wrong code might look ok for one example, while it might be completely wrong in general – 463035818_is_not_an_ai May 06 '16 at 09:33
  • Thanks for the quick reply.I know what you mean, thank you very much. While, that's why i say I don't know in which case there will be wrong and want to see some codes that can show me the potential problem. – hitwlh May 06 '16 at 09:35
  • If the book says that you have to make that promise, I would believe that book. If you dont keep that promise you are on your own, anything might happen, you might even get a result that looks fine even when in general it is not – 463035818_is_not_an_ai May 06 '16 at 09:35
  • Thanks for the quick reply. So I have to obey this rule~ – hitwlh May 06 '16 at 09:38
  • @hitwlh: in this example `int &&rr3 = std::move(rr1);` rr1 is simply an `int` for which memory is already allocated statically. So only when it will go out of scope then only its memory(read value) will become invalid. Otherwise `int rr4 = rr1` won't harm but you simply break the promise associated with using `move`. – sameerkn Dec 28 '16 at 07:36
  • @hitwlh: Now, `CPerson p1("alex"); CPerson p2=move(p1); CPerson p3 = p1;` would cause problem if `Cperson` allocated memory dynamically for "alex" and `Cperson`'s `move copy ctor` transfers the dynamically allocated memory from `p1` to `p2`. So now `p3=p1` is problematic because `p1` does not have a valid memory inside it. – sameerkn Dec 28 '16 at 07:36

2 Answers2

0

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.

Pete Becker
  • 74,985
  • 8
  • 76
  • 165
0

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;
sameerkn
  • 2,209
  • 1
  • 12
  • 13