The grass is definitely greener. In Rust you never have any doubts about whether you're moving or copying. Although...
Rust's 'move semantics' are defined as copying the value, including any internal references. That's also what happens in C++, of course, and normally 'the value' is a small struct with potential heap references embedded. But it's possible to embed a large array in a struct, in which case moving it is expensive-
Except usually not, as the memory copy only exists in principle and the optimiser will usually remove it. But that isn't visible at the language level.
It's also nice that the moved-from value cannot be used afterwards. No need to wonder if it's in a sensible state or not -- the type system won't let you access it. (Which is why the optimiser is fairly reliable at reusing the data.)
> It's also nice that the moved-from value cannot be used afterwards.
There are a few cases in low-level systems code where being able to defer destruction of the moved-from value is useful. A common example is when there is no way to enforce ownership semantics on the resource at compile-time e.g. direct I/O or similar types of shared address space. Being able to safely move the value immediately does not imply that you can safely destroy the moved-from value immediately as long references not visible from your address space exist.
The non-trivial moves in C++ are convenient for wiring in the necessary mechanics, automagically ensuring the moved-from value lives long enough for the exogenous references to discover it has been moved. You can do this manually without non-trivial moves but the syntactic sugar makes some things that are inherently memory-dangerous much safer.
> Except usually not, as the memory copy only exists in principle and the optimiser will usually remove it. But that isn't visible at the language level.
that's the biggest difference form C++: a copy or move can, in principle, have observable side effects, so, aside from specifically santioned copy/move elision scenarios, the compiler cannot elide a copy or move constructor unless it can prove there are no visible side effects (usually by inlining the copy/move constructor and optimizing it away).
On the other hand this allows more flexible copy/move behaviour beyond just handling memory.
Rust's 'move semantics' are defined as copying the value, including any internal references. That's also what happens in C++, of course, and normally 'the value' is a small struct with potential heap references embedded. But it's possible to embed a large array in a struct, in which case moving it is expensive-
Except usually not, as the memory copy only exists in principle and the optimiser will usually remove it. But that isn't visible at the language level.
It's also nice that the moved-from value cannot be used afterwards. No need to wonder if it's in a sensible state or not -- the type system won't let you access it. (Which is why the optimiser is fairly reliable at reusing the data.)