Drop and Resource Management
RAII
RAII (Resource Acquisition Is Initialization, also known as Scope-Bound Resource Management or SBRM) is the idiom in which a resource's lifetime is bound strictly to the lifetime of a stack-allocated object: the constructor acquires the resource and establishes invariants, and the destructor (Drop::drop) releases the resource when the object goes out of scope.
Core Principles of RAII in Rust
- No half-initialized states: Constructors (
File::open,Mutex::lock,TcpStream::connect) returnResult<Guard, Error>rather than an uninitialized object that requires a separate.init()call. If acquisition fails, no object is constructed and no destructor runs. - Access mediated through the guard: The resource can only be used through methods or
Derefon the RAII object, making use-after-close or unlocked access impossible at compile time. - Move semantics prevent double release: Because Rust moves values by default (and forbids
Copyon types implementingDrop), transferring an RAII handle to another function or thread transfers responsibility for running the destructor without duplicating the handle.
RAII Lifecycle:
Constructor (`acquire()`)
|
+-- Failure -> Returns `Err(E)` (No guard created, no Drop needed)
|
+-- Success -> Returns `Ok(Guard)`
|
v
Guard In Scope (Resource active & accessible)
|
v
Scope Exit / Unwind -> `Guard::drop(&mut self)` releases resource
Standard Library RAII Guards
| RAII Type | Acquisition Function | Resource Released in Drop |
|---|---|---|
Box<T>, Vec<T>, String |
Box::new, Vec::with_capacity |
Heap memory via GlobalAlloc::dealloc |
std::fs::File |
File::open, File::create |
Operating system file descriptor (close / CloseHandle) |
MutexGuard<'_, T> |
Mutex::lock, Mutex::try_lock |
Mutex lock state |
RwLockReadGuard<'_, T>, RwLockWriteGuard<'_, T> |
RwLock::read, RwLock::write |
Reader or writer lock state |
Ref<'_, T>, RefMut<'_, T> |
RefCell::borrow, RefCell::borrow_mut |
Dynamic borrow flag in RefCell<T> |
PeekMut<'_, T> |
BinaryHeap::peek_mut |
Sifts modified top element back into heap order |
Building a Custom RAII Guard
A custom RAII guard encapsulates a setup action in its constructor and a guaranteed teardown action in its Drop implementation—even if intermediate operations return early or panic:
use std::cell::Cell;
struct IndentationGuard<'a> {
depth: &'a Cell<usize>,
}
impl<'a> IndentationGuard<'a> {
fn enter(depth: &'a Cell<usize>, section: &str) -> Self {
let current = depth.get();
println!("{:indent$}<{}>", "", section, indent = current * 2);
depth.set(current + 1);
Self { depth }
}
}
impl Drop for IndentationGuard<'_> {
fn drop(&mut self) {
let next = self.depth.get() - 1;
self.depth.set(next);
println!("{:indent$}</>", "", indent = next * 2);
}
}
fn main() {
let depth = Cell::new(0);
let _root = IndentationGuard::enter(&depth, "html");
{
let _body = IndentationGuard::enter(&depth, "body");
{
let _p = IndentationGuard::enter(&depth, "p");
println!("{:indent$}Hello, RAII!", "", indent = depth.get() * 2);
}
}
}
<html>
<body>
<p>
Hello, RAII!
</>
</>
</>