Right now the only way to enforce this is by convention: 1. move/unique/shared_ptr=receiver allowed to keep pointer, 2. raw ptr=totally banned, 3. reference=caller must outlive callee and called function is not allowed to keep pointer after returning. The last scenario here is not enforcable by the compiler.
I've referred to the attempts to fix C++ ownership semantics with templates as "wallpapering over the mold".
Yeah, basically that it's quite difficult to implement especially with C++'s baggage and undefined behaviour, from what I remember
In Rust, assignment and argument passing always move, "moving" always does the right thing (make a shallow copy and invalidate the original object), and you can't override this behavior. Furthermore, Rust splits what C++ calls "copying" into two concepts: shallow copying (which is the same as moving, except the original object isn't invalidated, and the type checker guarantees you can only do it when it makes sense) and deep cloning (which may be expensive and needs to be explicitly requested by the programmer).
This is why Rust can track which objects are no longer usable.
MovableObject a, b, c;
b = std::move(a);
c = std::move(a);
`c` may contain garbage.BTW the "move trait" (as its called in rust) is a related but orthogonal concept to its borrow checker.