Ownership is Rust’s compile-time memory management strategy: the compiler tracks which variable owns each value and inserts the drop (deallocation) automatically when the owner goes out of scope.
Why ownership?
C/C++ rely on the programmer to free memory correctly. Garbage-collected languages pay runtime cost and unpredictable pause times. Ownership gives C++-style predictability with compile-time guarantees that no double-free, use-after-free, or leak slips through.
The three rules:
Every value has a variable that is its owner
There can be only one owner at a time
When the owner goes out of scope, the value is dropped
Move semantics
let s1 = String::from("hello");let s2 = s1; // ownership moves to s2println!("{}", s1); // compile error: s1 was moved
If both s1 and s2 pointed at the same heap buffer, dropping both would double-free. Rust forbids that statically by invalidating s1.
Copy vs Move
Simple types (integers, bools, floats) implement the Copy trait and use copy semantics, since copies are cheap and moves would be cumbersome. Heap-backed types like String and Vec<T> move by default. .clone() is the explicit opt-in for a deep copy.
Passing a value to a function and returning it follow the same rules: arguments are moved (or copied) in, return values move out.
C++ RAII has one owner too, but the C++ compiler doesn’t enforce it, so you can still write code that breaks the invariant and segfaults.
What ownership prevents
Memory leak, owner going out of scope always drops
Double-free, one owner means one drop
Use-after-free, a moved value can’t be referenced
Reading uninitialized memory, caught by the compiler
Stack value escaping its scope, compiler forces a move or copy