Channels ▼

Andrew Koenig

Dr. Dobb's Bloggers

Why Moving An Object Does Not Destroy the Original

September 15, 2011

When I first learned about how C++ moves data, I thought there must have been a design mistake. Suppose we have a variable named source, and we move that variable into another variable named dest:

string source = "This is a string";
string dest = std::move(source);

The C++ standard says that after we have executed these statements, source has an unspecified value, but that value is valid. If the reason we moved the data from source rather than copying it is that we do not intend to use source again, why is it important for source still to be valid? Isn't that design decision a mistake? Wouldn't it be better simply to destroy source? That way, when we moved data out of source, we would not need to put new data into source to ensure its validity.

Of course, if moving data from source destroys source, the compiler would have to know that source was destroyed:

{ string source = "This is a string";
  string dest = std::move(source); }

Ordinarily, the compiler would execute the destructors for dest and source at the }, but after the call to std::move, the compiler would have to know that source had already been destroyed and not do so a second time.

Still, I thought, there's no reason the compiler couldn't figure such things out. Why require the move constructor to store data merely for the benefit of the destructor?

The example that convinced me that there was no design error was what happens when we call an algorithm that removes a number of elements from a container that is not known until runtime:

vector<int> v;

// …

remove(v.begin(), v.end(), 42);

The call to remove "removes" all instances of the value 42 from v, by copying all the elements of v with values unequal to 42 to the beginning, and leaves some number of elements at the end of v with unspecified values. Moreover, it does so without changing the length of v. If moving a variable destroyed the original, then how would the library be able to destroy v? There would be elements at the end of v that were already destroyed and must not be destroyed again.

Nor would it do to have remove change the length of v. Remember that remove can take any appropriate pair of iterators as arguments. In particular, it can take a pair of pointers to elements of an array — and there is no way to change the length of an array once it has been allocated. So if moving a variable destroyed the original, there would have to be some way of knowing which array elements had already been destroyed. Such knowledge might be contained in a flag associated with each element that indicates whether that element has a value that must be freed.

But if such a flag is to exist, why not make it part of the value? That is, why not say that when we move data out of source, we replace it by dummy data that permits source to be destroyed safely? Of course, once we have said that, we're right back where we started, namely with the requirement that source have a valid value but be otherwise unspecified.

This line of reasoning convinced me that the design decision was correct. It catered to the possibility that the library might not know which variables had been used as the source of move operations, and did so with only a small amount of extra runtime overhead. Moreover, as I’ve already mentioned, the amount of time it takes to give an appropriate dummy value to a data structure such as a string is tiny compared to the amount of overhead that moving data avoids compared with copying the data and destroying the original.

Related Reading

More Insights

Currently we allow the following HTML tags in comments:

Single tags

These tags can be used alone and don't need an ending tag.

<br> Defines a single line break

<hr> Defines a horizontal line

Matching tags

These require an ending tag - e.g. <i>italic text</i>

<a> Defines an anchor

<b> Defines bold text

<big> Defines big text

<blockquote> Defines a long quotation

<caption> Defines a table caption

<cite> Defines a citation

<code> Defines computer code text

<em> Defines emphasized text

<fieldset> Defines a border around elements in a form

<h1> This is heading 1

<h2> This is heading 2

<h3> This is heading 3

<h4> This is heading 4

<h5> This is heading 5

<h6> This is heading 6

<i> Defines italic text

<p> Defines a paragraph

<pre> Defines preformatted text

<q> Defines a short quotation

<samp> Defines sample computer code text

<small> Defines small text

<span> Defines a section in a document

<s> Defines strikethrough text

<strike> Defines strikethrough text

<strong> Defines strong text

<sub> Defines subscripted text

<sup> Defines superscripted text

<u> Defines underlined text

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task. However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

Disqus Tips To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy.



Mr. Koenig, in:

string source = "This is a string";
if (its_raining_in_boston())
string dest = std::move(source);

how could the compiler figure out at the "}" whether source had already been destroyed, unless the move operation always left it in a valid sate?

(One can complicate things for the compiler further by e.g. performing the move inside a function that is defined in another compilation unit, or by having multiple branching execution paths, only some of which perform the move, or by having the variable to be moved be selected at runtime using pointer arithmetic).