问题
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.
回答1:
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.
回答2:
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 << ".";
回答3:
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?
回答4:
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.
回答5:
_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?
回答6:
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.
来源:https://stackoverflow.com/questions/3128087/move-constructor-operator