What is Ownership? #
- Ownership is Rust’s unique memory management system that ensures memory safety without a garbage collector.
- It’s a set of rules enforced at compile time that determines how memory is allocated, accessed, and freed.
- Ownership prevents common memory bugs like dangling pointers, double frees, and memory leaks while maintaining zero-cost abstractions.
Ownership Rules #
Rust’s ownership system follows three fundamental rules:
1. Each value in Rust has an owner
let s = String::from("hello"); // 's' owns the String value
2. There can only be one owner at a time
let s1 = String::from("world");
let s2 = s1; // s1 is no longer valid, s2 is now the owner
3. When the owner goes out of scope, the value will be dropped
When a variable goes out of scope, Rust automatically calls a special function called drop() to clean up the memory, eliminating the need for manual memory management or garbage collection.
{
let s = String::from("temp");
} // 's' goes out of scope here, memory is automatically freed
Stack vs Heap Allocation #
| Aspect | Stack Allocation | Heap Allocation |
|---|---|---|
| Size | Fixed size, known at compile time | Dynamic size, unknown at compile time |
| Access Speed | Fast (LIFO – Last In, First Out) | Slower (requires pointer dereferencing) |
| Memory Management | Automatic cleanup when scope ends | Manual management (handled via ownership) |
| Typical Usage | Primitive and simple types (eg. int) | Complex and dynamically sized types (eg. string) |
Stack (Fast, Fixed Size) Heap (Flexible, Dynamic Size)
┌─────────────────────┐ ┌─────────────────────────────┐
│ i32: 42 │ │ String data: "hello world" │
│ bool: true │ │ Vec data: [1, 2, 3, 4, 5] │
│ char: 'A' │ │ HashMap data: {...} │
│ pointer to heap ────┼──────────┤ │
└─────────────────────┘ └─────────────────────────────┘
Shallow Copy vs Deep Copy #
| Aspect | Shallow Copy | Deep Copy |
|---|---|---|
| What gets copied | Only metadata (pointer, length, capacity) | Metadata and actual data |
| Data Ownership | Shared underlying heap data | Independent heap copies |
| Performance | Fast | Slower |
| Safety | Can lead to double-free or data corruption | Safer, no shared ownership issues |
Move, Clone, and Copy Scenarios #
1. Move #
Applies to heap / dynamic data types.
let s1 = String::from("hello");
let s2 = s1; // s1 is MOVED to s2
// println!("{}", s1); // Compile error! s1 is no longer valid
println!("{}", s2); // Works fine
2. Assigning New Value to Existing Variable #
let mut s = String::from("hello");
s = String::from("world"); // Old "hello" is dropped immediately
println!("{}", s); // Prints "world"
3. Clone #
It is an explicit Deep Copy
let s1 = String::from("hello");
let s2 = s1.clone(); // Explicit deep copy
println!("s1: {}, s2: {}", s1, s2); // Both valid
4. Copy #
Applies to Stack only types that support “Copy” trait.
Example: Integer i32 type implements “Copy” trait and it has a fixed size hence it is trival to copy as it sits on stack
let x = 5;
let y = x; // Copy semantics (both remain valid)
println!("x: {}, y: {}", x, y); // Both valid
Types that implement Copy:
- All integer types (
i32,u64, etc.) - Boolean (
bool) - Floating point (
f32,f64) - Character (
char) - Tuples (if all elements implement Copy)
Understanding Traits: Copy vs Drop #
Traits in Rust define shared behavior that types can implement. Think of them as contracts that specify what a type can do.
// Trait example (simplified)
trait Copy {
// Types implementing Copy can be duplicated by copying bits
}
trait Drop {
fn drop(&mut self) {
// Custom cleanup code when value goes out of scope
}
}
Copy and Drop are mutually exclusive:
- Copy trait: Types that can be safely duplicated by simply copying their bits (stack-only data)
- Drop trait: Types that need custom cleanup when going out of scope (usually heap-allocated data)
Why they can’t coexist: If a type implements Copy, Rust assumes it’s safe to duplicate by copying bits. But if it also needs Drop (custom cleanup), copying would create multiple owners of the same resources, leading to the double-free problem ownership is designed to prevent.