drop and automatic cleanup
In C, every malloc must be matched by exactly one free, and you place that free by hand at the right spot — which is forgettable on a normal path and very easy to skip on an error path that returns early. Rust takes that obligation off your hands. When an owning value goes out of scope — when the block it lives in ends — Rust automatically runs its cleanup. This automatic cleanup is called drop, and the rule is simple: the value's owner reaching the end of its scope is the cue to release whatever the value holds.
Concretely, when a variable that owns a resource goes out of scope, Rust inserts the cleanup for you. For a String or a Vec<T>, drop frees the heap memory the value owned; for a file handle, drop closes the file; for a lock guard, drop releases the lock. You do not write free and you usually do not write drop — the compiler emits the call at the closing brace where the owner dies, in reverse order of declaration. Because ownership guarantees exactly one owner, drop runs exactly once for each value, at exactly one well-defined moment, so there is no double-free and nothing to forget. This is the Rust form of a pattern C++ programmers call RAII — tying a resource's release to the lifetime of the object that owns it.
Why this matters: drop is the mechanism that makes ownership pay off in practice. It is what lets Rust promise no leaks from forgetting to free and no use-after-free, without a garbage collector pausing your program — cleanup happens at a precise, predictable point you can reason about, the moment the owner's scope ends, decided at compile time. The honest caveats are worth keeping straight. drop runs by scope, not by magic, so a value held alive longer than you meant (for instance stored in a long-lived structure) frees later than you might expect. And Rust still does not stop you from leaking on purpose — you can intentionally keep something alive forever or call std::mem::forget — so drop prevents accidental leaks, not all leaks.
{ let s = String::from("data"); // owns heap bytes let v = vec![1, 2, 3]; // owns heap bytes // ... use s and v ... } // scope ends: v dropped, then s dropped (reverse order), memory freed // no free() written anywhere
Cleanup is tied to the owner's scope; drop runs automatically at the closing brace.
drop runs once, automatically, when the owner's scope ends — that is what prevents leaks-by-forgetting and double-frees. It does not prevent leaks-on-purpose: a value kept alive forever, or std::mem::forget, never drops.