By fredoverflow


2011-08-11 14:19:12 8 Comments

Does the standard define precisely what I can do with an object once it has been moved from? I used to think that all you can do with a moved-from object is do destruct it, but that would not be sufficient.

For example, take the function template swap as defined in the standard library:

template <typename T>
void swap(T& a, T& b)
{
    T c = std::move(a); // line 1
    a = std::move(b);   // line 2: assignment to moved-from object!
    b = std::move(c);   // line 3: assignment to moved-from object!
}

Obviously, it must be possible to assign to moved-from objects, otherwise lines 2 and 3 would fail. So what else can I do with moved-from objects? Where exactly can I find these details in the standard?

(By the way, why is it T c = std::move(a); instead of T c(std::move(a)); in line 1?)

2 comments

@Howard Hinnant 2011-08-11 15:09:57

17.6.5.15 [lib.types.movedfrom]

Objects of types defined in the C++ standard library may be moved from (12.8). Move operations may be explicitly specified or implicitly generated. Unless otherwise specified, such moved-from objects shall be placed in a valid but unspecified state.

When an object is in an unspecified state, you can perform any operation on the object which has no preconditions. If there is an operation with preconditions you wish to perform, you can not directly perform that operation because you do not know if the unspecified-state of the object satisfies the preconditions.

Examples of operations that generally do not have preconditions:

  • destruction
  • assignment
  • const observers such as get, empty, size

Examples of operations that generally do have preconditions:

  • dereference
  • pop_back

This answer now appears in video format here: http://www.youtube.com/watch?v=vLinb2fgkHk&t=47m10s

@fredoverflow 2011-08-11 15:17:16

But I could simply check the preconditions just like with any other object, right?

@Chris says Reinstate Monica 2011-08-11 15:18:33

@FredOverflow As long as these checks themselves have no preconditions, of course.

@Howard Hinnant 2011-08-11 15:20:18

@Christian: Exactly!

@fredoverflow 2011-08-11 15:25:58

@Chris: But how is that different from a normal, not moved-from object?

@Chris says Reinstate Monica 2011-08-11 15:27:45

@FredOverflow Who said a moved-from object is different from a non-moved object. That is the point in all the answers (well, except 6502's), a moved-from object is still a completely valid and usable object. You just don't know in which (valid) state it is. Like said, moving doesn't destroy the object, but alter it.

@Howard Hinnant 2011-08-11 15:30:02

@FredOverflow: The only difference is that most operations leave an object in a specified state. The moved-from state is unspecified, but otherwise, not special. Of course if you are the author of your class, you are free to make your moved-from state as special as you want. But know that if you use your class in std algorithms, your type is required to meet the stated requirements of the std algorithm, whether in a moved-from state or not ([utility.arg.requirements], Tables 20 and 22).

@UncleBens 2011-08-11 15:32:10

May-be should be a separate question, but does that mean: if I have a string with char* buffer; and int length; members, then my move constructor/assignment must swap (or set) the value of both? Or would it be OK, if the length was unspecified (meaning that empty and size return meaningless values)?

@6502 2011-08-11 15:33:42

Amazing how the standard uses "shall be placed in a valid but unspecified state" when the code that will do this operation is possibly generated by the compiler. All of a sudden we got classes that were perfectly valid and idiomatic in C++ and that in C++0X are violating the standard because C++0X will automatically generate a broken move constructor.

@Chris says Reinstate Monica 2011-08-11 15:34:32

@UncleBens In this case your string object would be in an invalid state, I think, which should answer your question. Not all unspecified states are valid, but only the valid ones should be taken by moved-from objects.

@fredoverflow 2011-08-11 15:52:12

@Uncle: I think that warrants its own question. You have my upvote for sure ;)

@Puppy 2011-08-11 16:33:23

@6502: Will you please stop just ranting on and on? This is not the place.

@6502 2011-08-11 19:21:18

@UncleBens: In you class probably if there is a move constructor or move assignment it would be written by you. The compiler will not generate a move operation for a class that has an explicit destructor.

@MSalters 2011-08-12 09:27:59

@6502: You don't make sense. A C++03 class isn't "violating the C++0x standard" because a move ctor if generated would violate the standard. And C++03 code wouldn't be moving that class so there's no reason for a move ctor to be generated.

@6502 2011-08-12 11:40:35

@MSalters: C++03 code can well put an object in an std::vector and call std::sort on that vector. The resulting code will possibly use move semantic including assignment to a moved-from object when compiled in C++0X mode. This by the way is not the only incompatible change... even just std::vector<X> v(n); has a different semantic in C++0X.

@sdenham 2017-03-26 14:38:14

@UncleBens If empty or size (or any member function) might return meaningless values, the class would be effectively unusable. Also, if the buffer's storage was dynamically allocated by the class, you have to ensure that it is freed at some point, and that also applies to the buffer held by the target prior to the move. Furthermore, the source object's destructor must not apply free to an invalid address, or to the address it moved to the target. Swapping satisfies these rules, as, presumably, does freeing the destination's original buffer and setting the source to {0,nullptr}.

@Puppy 2011-08-11 14:30:45

Moved-from objects exist in an unspecified, but valid, state. That suggests that whilst the object might not be capable of doing much anymore, all of its member functions should still exhibit defined behaviour — including operator= — and all its members in a defined state- and it still requires destruction. The Standard gives no specific definitions because it would be unique to each UDT, but you might be able to find specifications for Standard types. Some like containers are relatively obvious — they just move their contents around and an empty container is a well-defined valid state. Primitives don't modify the moved-from object.

Side note: I believe it's T c = std::move(a) so that if the move constructor (or copy constructor if no move is provided) is explicit the function will fail.

@Howard Hinnant 2011-08-11 14:40:51

Not all of its member functions will exhibit defined behavior. Only those with no preconditions. For example you probably don't want to pop_back a moved-from vector. But you can certainly find out if it is empty().

@Puppy 2011-08-11 14:50:25

@Howard Hinnant: pop_back from an empty vector has undefined behaviour anyway, from memory, so I'm pretty sure that pop_back from a moved vector exhibiting undefined behaviour is consistent.

@Howard Hinnant 2011-08-11 15:11:29

We're discussing moved-from objects. Not objects known to be in an empty state. Moved-from objects have an unspecified state (unless of course otherwise specified). [lib.types.movedfrom]

@Chris says Reinstate Monica 2011-08-11 15:15:42

@Howard Unspecified, but valid, so pop_back still behaves like on any valid vector (may it even be an empty vector).

@Red XIII 2013-02-01 16:15:56

I understand it as follows: the state of the object after moving can be in any valid state, and all the actions valid for the state can still be used. If the committee wanted they would have to go great lengths of specifying every possible state of object.

@Ankur S 2018-06-19 12:41:28

what do unspecified and valid mean in this context?

@Simon 2019-09-12 14:17:55

Defined behavior does not mean a defined result. So taking the example of a moved-from vector, one can find out if it is empty(), but one cannot expect that this returns a specified result, be it true or false.

Related Questions

Sponsored Content

12 Answered Questions

[SOLVED] What are rvalues, lvalues, xvalues, glvalues, and prvalues?

23 Answered Questions

[SOLVED] What is the "-->" operator in C++?

9 Answered Questions

[SOLVED] What is a lambda expression in C++11?

37 Answered Questions

21 Answered Questions

[SOLVED] Why should I use a pointer rather than the object itself?

  • 2014-03-03 11:54:16
  • gEdringer
  • 299238 View
  • 1538 Score
  • 21 Answer
  • Tags:   c++ pointers c++11

13 Answered Questions

[SOLVED] What is a smart pointer and when should I use one?

11 Answered Questions

[SOLVED] What is move semantics?

24 Answered Questions

[SOLVED] Image Processing: Algorithm Improvement for 'Coca-Cola Can' Recognition

11 Answered Questions

[SOLVED] What does the explicit keyword mean?

Sponsored Content