Remix.run Logo
malkia 3 days ago

Yup - I wish that was not the case, I've learned relatively recently that the state the variable becomes (after moving) is "valid, but unspecified" - e.g. you can still destroy it (I guess how would RAII work otherwise), you can still assign to it, and even check some basic properties (!) - but you can't know anything about the actual value (contents) it carries (weird)

It's like a tombstone for a deleted file, object - something that tells you - "Here lived Obj B Peterson, was nice folk, but moved away to a higher place"

vitus 3 days ago | parent | next [-]

> "valid, but unspecified"

Annoyingly, it depends on the type, sometimes with unintuitive consequences.

Move a unique_ptr? Guaranteed that the moved-from object is now null (fine). Move a std::optional? It remains engaged, but the wrapped object is moved-from (weird).

Move a vector? Unspecified.

senderista 3 days ago | parent | prev [-]

Those semantics are entirely on you, the implementer, to enforce. Move semantics is basically a contract between move ctor/assignop impls and dtor impls: the former must somehow signal moved-out status (typically by nulling out a ptr or setting a flag), and the latter must respect it. And of course the client shouldn't use a moved-from object in invalid ways. All of this is completely ad-hoc and unenforceable.

malkia 3 days ago | parent [-]

Well, it's not on me, because I'm often the user of someones library, framework, etc, and then it's up to whether it was concious or unconcious decision that the type behaved that way, and then you have to mix things to work together and you end up with this really "unspecified" way, hence you put some rules - "Don't do this" - don't use object after std::move, even if it might be allowed.

I'm still baffled.

senderista 3 days ago | parent [-]

Well they couldn't do much better without supporting destructive moves. Rust shows how simple move semantics can be when they're designed into the language.