Move Semantics
An assignment will transfer ownership between variables:
fn main() { let s1 = String::from("Hello!"); let s2 = s1; dbg!(s2); // dbg!(s1); }
- The assignment of s1tos2transfers ownership.
- When s1goes out of scope, nothing happens: it does not own anything.
- When s2goes out of scope, the string data is freed.
Before move to s2:
After move to s2:
When you pass a value to a function, the value is assigned to the function parameter. This transfers ownership:
fn say_hello(name: String) { println!("Hello {name}") } fn main() { let name = String::from("Alice"); say_hello(name); // say_hello(name); }
- 
Mention that this is the opposite of the defaults in C++, which copies by value unless you use std::move(and the move constructor is defined!).
- 
It is only the ownership that moves. Whether any machine code is generated to manipulate the data itself is a matter of optimization, and such copies are aggressively optimized away. 
- 
Simple values (such as integers) can be marked Copy(see later slides).
- 
In Rust, clones are explicit (by using clone).
In the say_hello example:
- With the first call to say_hello,maingives up ownership ofname. Afterwards,namecannot be used anymore withinmain.
- The heap memory allocated for namewill be freed at the end of thesay_hellofunction.
- maincan retain ownership if it passes- nameas a reference (- &name) and if- say_helloaccepts a reference as a parameter.
- Alternatively, maincan pass a clone ofnamein the first call (name.clone()).
- Rust makes it harder than C++ to inadvertently create copies by making move semantics the default, and by forcing programmers to make clones explicit.
More to Explore
Defensive Copies in Modern C++
Modern C++ solves this differently:
std::string s1 = "Cpp";
std::string s2 = s1;  // Duplicate the data in s1.
- The heap data from s1is duplicated ands2gets its own independent copy.
- When s1ands2go out of scope, they each free their own memory.
Before copy-assignment:
After copy-assignment:
Key points:
- 
C++ has made a slightly different choice than Rust. Because =copies data, the string data has to be cloned. Otherwise we would get a double-free when either string goes out of scope.
- 
C++ also has std::move, which is used to indicate when a value may be moved from. If the example had beens2 = std::move(s1), no heap allocation would take place. After the move,s1would be in a valid but unspecified state. Unlike Rust, the programmer is allowed to keep usings1.
- 
Unlike Rust, =in C++ can run arbitrary code as determined by the type which is being copied or moved.