That's nice. The speaker says that C++ code with std::move works in-place and doesn't perform memory allocations. The Rust version could do the same, re-using the given moved String.
Yes, both signatures I gave you will work in-place and not perform allocations, one by move (which is why it's the direct translation) and one by mutable reference.
Moved values live on the call-ee's stack frame. Values are moved by byte-copying the stack part. There's no move constructors.
In the case of String, the pointer, length, and capacity fields get copied, while the heap part (which contains the actual string data) is simply left alone. The same analysis that prevents you from calling a method on a moved value is also used by the compiler to avoid calling a destructor on a moved value, so the destructor is called by the call-ee, not the call-er.
To give you even more unbidden-for information, rustc classifies variables into "definitely moved", "possibly moved", "definitely not moved".
If it's definitely not moved, the destructor call gets inserted.
If it's definitely moved, the destructor call doesn't get inserted.
If it's possibly moved, like with this code:
fn might_move_the_string() {
let s = String::new();
if flip_coin() { clean_whitespace(s); }
}
into something like this:
fn might_move_the_string_compiled_pseudo_rust() {
let s = String::new();
let mut s_drop_flag = true; // this variable is magically inserted by the compiler
if flip_coin() { s_drop_flag = false; clean_whitespace(s); }
if s_drop_flag { drop(s) }
}