Pergunta

I'm trying to learn about new feature of C++ namely move constructor and assignment X::operator=(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 memory-leak and one expression less afaics.

Foi útil?

Solução

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.

Outras dicas

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 << ".";

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?

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.

_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?

Setting the value to zero will only expose consistency. However, the answer really depends on how intend to use _length for the destruction of the object. If length is not used to determine if _data should be deleted (when the moved object falls out of scope), then we can say it is safe to ignore _length when moving the object. Just make sure you keep this consistency in any derived types, and make sure that your decision to ignore _length is documented.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top