views:

115

answers:

5

I'm trying to learn about new feature of C++ namely move constructor and assignment X::operaror=(X&&) and I found interesting example but the only thing I quite not even understand but more dissagree is one line in move ctor and assignment operator (marked in the code below):

MemoryBlock(MemoryBlock&& other)
   : _data(NULL)
   , _length(0)
{
   std::cout << "In MemoryBlock(MemoryBlock&&). length = " 
             << other._length << ". Moving resource." << std::endl;

   // 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 so that
   // the destructor does not free the memory multiple times.
   other._data = NULL;
   other._length = 0;//WHY WOULD I EVEN BOTHER TO SET IT TO ZERO? IT DOESN'T MATTER IF IT'S ZERO OR ANYTHING ELSE IT IS JUST A VALUE.
}

So my question is: do I have to set the value of lenght_ to zero or can I leave it untouched? There won't be any mem. leak and one expression less. IMO.
Thanks

+5  A: 

Because the "moved from" object is still going to be destructed eventually, so you have to leave it in a consistent state. Exactly how you do this depends on your object, of course, and in this case it apparently means nulling out the data pointer and setting the length to zero.

Terry Mahaffey
@Terry but why does it make a difference if there is zero or thousand? It is still valid int.
There is nothing we can do
@A-ha There is a difference between a valid value and a correct/consistent value.
Josh Matthews
@Josh Not in this case AFAIC
There is nothing we can do
@All can't f...ing belive it this answer gets upvotes.
There is nothing we can do
Its unbelievable that people would upvote correct answers. What insolence.
Dennis Zickefoose
@Terry after some thought yes you are right. I do accept your answer.
There is nothing we can do
A: 

Appearantly, the programmer decided that length should always have a correct value. If you do not set it, the code in the destructor will no longer print the correct thing:

std::cout << "In ~MemoryBlock(). length = "
                << _length << ".";
Sjoerd
@Sjoerd you do not understand what my question is.
There is nothing we can do
@Sjoerd You are just wrong. It doesn't matter if I assign zero or not. Value in dtor will still be printed.
There is nothing we can do
@A-ha: if you do not set other._length to `0`, it still outputs as `0` in the destructor?
Bill
@Bill but in dtor it prints the values set in ctor (doesn't matter if you set lengt_ to zero or not).
There is nothing we can do
A: 

_length and _data are semantically related items. For an object to be in a consistent state, _length should always tell you how much memory is in the block pointed to by _data. When _data points to 100 blocks, _length should be 100. When _data points to 1 block, _length should be 1. If _data doesn't point to anything (NULL), then _length should be 0. Otherwise, if _data is NULL and _length is 100, then your object is in an inconsistent state. When I do:

for (int i = 0; i < _length; ++i)
{
  // do something with _data[i], such as:
  _data[i] = 0;
}

I should not crash. If you fail to set _length correctly, it will crash. The real question is, why would you intentionally leave the object in an inconsistent state which will lead to crashes?

Bill
@Bill but in this scenario you have correct length_ already assign in the line above. What is done in a line I'm talking about is only to nullify the tmp object so I say it again: No it doesn't matter in my opinion what the value of length_ will be.
There is nothing we can do
@Bill continue in nullified object.
There is nothing we can do
@A-ha: `other._length` is only set in one place: `other._length = 0;` Logically, your opinion is that it is OK to leave an object in an inconsistent state. I disagree.
Bill
@Bill but what is incositent about it's state without leaving length_ untouched? Nothing. And the more I think about it the more I'm convinced that even the line other._data = NULL is just for safety pourposes (just to have pointer pointed to "nothing").
There is nothing we can do
@A-ha: if the destructor has to do something with the memory besides calling delete (such as calling the destructor on objects stored in the block) then your code will crash if `_length` is not set correctly. In this _specific_ instance the destructor only calls `delete`, and ignores the value of `_length`. However, counting on code to never change is a great source of potential errors. (For example, place the `for` loop in my answer in the destructor and watch the segfault.)
Bill
A: 

It is hard to get a definitive answer to this question. Move semantics are new and the C++ community is still learning how to use it correctly.

One reasonable rule that I saw is that the "moved away from" object must destruct safely and be able to be assigned a new value. Setting _length to zero is not necessary to satisfy that rule, and frankly I am not sure what would be a good value for an int to indicate invalid state; maybe -1 in your case?

Nemanja Trifunovic
A: 

The object you are moving the data from might not be a temporary (you may use std::move for example) - it would be bad form to leave your object in an invalid state.

DanDan
@DanDan so reseting its values would be acceptable according to you? Interesting, interesting...
There is nothing we can do
Yes, because this is what the move constructor is for. You are transferring ownership of the contents of one object to another.
DanDan