6.1 The Ownership System
In Rust, every value has a variable that is its owner. The ownership system is governed by a simple set of rules enforced at compile time by the borrow checker:
- Single Owner: Each value in Rust has exactly one owner at any given time.
- Scope-Bound Lifetime: When the owner goes out of scope, the value it owns is dropped (its resources, like memory, are automatically deallocated).
- Ownership Transfer (Move): Assigning a value from one variable to another, or passing it by value to a function, moves ownership. The original variable becomes invalid.
This system prevents common memory errors like double frees (since only one owner can drop the value) and use-after-free (since variables become invalid after moving ownership).
If custom cleanup logic is needed when a value is dropped (e.g., releasing file handles or network sockets), you can implement the Drop
trait, similar in concept to a C++ destructor.
6.1.1 Scope and Automatic Cleanup (Drop
)
Consider this Rust code:
fn main() { { let s = String::from("hello"); // s comes into scope, allocates memory // ... use s ... } // s goes out of scope here. Rust calls drop on s, freeing its memory. }
When s
goes out of scope, Rust automatically calls the necessary cleanup code for String
, freeing its heap-allocated buffer.
6.1.2 Comparison with C
In C, the equivalent requires manual intervention:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main() {
{
char *s = malloc(6); // Allocate memory
if (s == NULL) { /* handle allocation error */ return 1; }
strcpy(s, "hello");
// ... use s ...
free(s); // Manually free the memory is crucial
} // Forgetting free(s) causes a memory leak.
return 0;
}
Rust’s automatic dropping based on scope prevents leaks without requiring manual free
calls.