Remix.run Logo
ghm2180 6 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.

qbane an hour ago | parent | next [-]

I read Effective Modern C++ years ago and was confused exactly like what you describe.

yunnpp 4 hours ago | parent | prev | next [-]

I thought "move doesn't move" was a fairly common C++ mantra at this point.

locknitpicker 4 hours ago | parent [-]

> 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.

LexiMax 2 hours ago | parent [-]

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.

jandrewrogers an hour ago | parent [-]

It solves some rare edge cases where the destruction of the moved-from object must be deferred -- the memory is still live even if the object is semantically dead. Non-destructive moves separate those concerns.

There is a related concept of "relocatable" objects in C++ where the move is semantically destructive but the destructor is never called for the moved-from object.

C++ tries to accommodate a lot of rare cases that you really only see in low-level systems code. There are many features in C++ that seem fairly useless to most people (e.g. std::launder) but are indispensable when you come across the specific problem they were intended to solve.

dsnr 5 hours ago | parent | prev | next [-]

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.

bitbasher 5 hours ago | parent | next [-]

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.

Conscat 4 hours ago | parent [-]

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.

anematode 3 hours ago | parent [-]

A loss of functionality, but arguably a good thing, e.g. moving will never throw an exception/panic so you don't need an equivalent to is_nothrow_move_constructible

grogers 4 hours ago | parent | prev | next [-]

> 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)

jjmarr 3 hours ago | parent | prev [-]

> 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.

masklinn 2 hours ago | parent [-]

> you can call functions on it

Only functions with no preconditions, unless the type makes more guarantees as to the moved-from state.

jjmarr 24 minutes ago | parent [-]

The guarantees is that a moved-from state is in an otherwise valid state.

So, you can do things like check if a moved from std::vector is empty (often the case in practice), then start appending elements to it.

QuercusMax 5 hours ago | parent | prev [-]

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.