There is a discussion that without rust's move semantics C++ cannot reach the safety levels of Rust. But rust's move semantic cannot be brought to C++ without breaking an existing code.[1]
In a short, C++ approach is to give any object a "blank state" which it must turn into after the value was moved from it. It is an attempt to track state "value was moved out" dynamically. Rust tracks it statically by treating a variable whose value was moved out as uninitialized variable and ensuring that are no accesses to uninitialized variables.
Yeah, I do understand the main principle behind it, and I think an address sanitizer helps here - I did some tests and the ASAN coming with Clang 14.0.0 catches the bug (at runtime, of course).
It's a different approach, and definitely less efficient than compile-time checking, but if your program is not too complex I think it's OK. Especially if you use such sanitizers at the unit test level.
I don't have enough experience to say if it actually works in general though, because as usual everything on paper is always working.
In a short, C++ approach is to give any object a "blank state" which it must turn into after the value was moved from it. It is an attempt to track state "value was moved out" dynamically. Rust tracks it statically by treating a variable whose value was moved out as uninitialized variable and ensuring that are no accesses to uninitialized variables.
[1] https://www.thecodedmessage.com/posts/cpp-move/