I was rather surprised to learn that the move constructor (and assignment for that matter) of std::optional
does not reset the optional moved from, as can be se
Unless otherwise specified, a moved-from object of class type is left in a valid but unspecified state. Not necessarily a "reset state", and definitely not "invalidated".
For primitive types , moving is the same as copying, i.e. the source is unchanged.
The defaulted move-constructor for a class type with primitive members will move each member, i.e. leave the primitive members unchanged; a user-defined move constructor might or might not "reset" them.
A moved-from vector may or may not still have elements in it. We would expect it not to, since that's efficient, but it cannot be relied on.
A moved-from std::string
may still have elements in it, because of Small String Optimization.
move
on std::optional
is actually specified by the standard (C++17 [optional.ctor]/7). It is defined as doing move
on the contained type, if present. It does not turn a valued optional into a valueless optional.
So it is actually expected that your code outputs true true
, and the actual contained value in foo
should stay the same too.
Regarding the question of why std::optional
's move-constructor is defined this way: I can't say for sure; but an optional
is not like a vector with max size of 1. It's more like a variable with a validity flag tacked on. Accordingly, it makes sense for moving an optional
to be like moving the variable.
If moving an optional
left the old one "empty", then a = std::move(b);
would invoke the destructor of b
's managed object, which would be unexpected (to me, at least).