Comment by ghm2180
9 hours ago
> Let me put this in simpler terms: std::move is like putting a sign on your object “I’m done with this, you can take its stuff.”
and later:
> Specifically, that ‘sign’ (the rvalue reference type) tells the compiler to select the Move Constructor instead of the Copy Constructor.
This is the best conceptual definition of what `std::move` is. I feel that is how every book should explain these concepts in C++ because its not a trivial language to get into for programmers who have worked with differently opiniated languages like python and java.
If you read Effective Modern C++ right Item 23 on this, it takes quite a bit to figure out what its really for.
In simpler terms
1. You must implement a move constructor or a move assignment operator in order for std::move to do anything
2. The moved object could be left in an unusable state, depending on your implementation, after stealing its internal resources.
I never understood move semantics until I learned Rust. Everything is move by default and the compiler makes sure you never leave things in an unusable state.
This was a difficult mental hurdle to get over with Rust, but once you do, move semantics make a lot more sense.
edit: When I said everything is move by default, I mean everything that isn't "Copy", such as integers, floats, etc.
What Rust loses with that decision is the ability to program the "semantics" in move semantics. Rust has no distinction between hypothetical place constructor and value constructor.
2 replies →
> You must implement a move constructor or a move assignment operator in order for std::move to do anything
Bit of a nitpick, but there are sometimes other functions with overloads for rvalue references to move the contents out - think something like std::optional's `value() &&`. And you don't necessarily need to implement those move constructor/assignment functions yourself, typically the compiler generated functions are what you want (i.e. the rule of 5 or 0)
> The moved object could be left in an unusable state, depending on your implementation, after stealing its internal resources.
The "proper" semantics are that it leaves the object in a valid but unspecified state. So, invariants still hold, you can call functions on it, or assign to it.
> you can call functions on it
Only functions with no preconditions, unless the type makes more guarantees as to the moved-from state.
1 reply →
I thought "move doesn't move" was a fairly common C++ mantra at this point.
> I thought "move doesn't move" was a fairly common C++ mantra at this point.
It is. The fact that std::move is just a cast and that move constructors are expected to transfer resources are basic intro to C++ topics, covered in intro to constructors.
It's far too late to put the genie back in the bottle, but I am morbidly curious as to why the standards committee didn't choose an approach that made moves destructive.
5 replies →
I read Effective Modern C++ years ago and was confused exactly like what you describe.
Modern C++ is hard to get into for people who learned C++ in the 90s and then worked in other languages for a decade or two.