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:

  1. Single Owner: Each value in Rust has exactly one owner at any given time.
  2. Scope-Bound Lifetime: When the owner goes out of scope, the value it owns is dropped (its resources, like memory, are automatically deallocated).
  3. 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.