liveBook · Manning

Resource acquisition is initialization

As explained in Idiomatic Rust

Resource acquisition is initialization is a resource-management pattern in which acquiring a resource is tied to initializing an object and releasing it to that object's destruction.

Resource acquisition is initialization (RAII) ties a resource to an object's lifetime: acquire it when the object is initialized, then release it when the object is destroyed. Its practical value is cleanup that follows scope, including when a function returns early. In C, returning after a failed file-open attempt can leave previously allocated memory unfreed; a C++ smart pointer instead releases its resource when it leaves scope. section 4.1 section 4.1.1

In Rust, ownership and move semantics make the cleanup point easier to reason about. When an owning value leaves scope, Rust calls its destructor; implement the Drop trait to give a resource-owning type custom cleanup. A move transfers ownership rather than creating a second owner. Copy values are an important exception: they cannot implement Drop, so do not depend on destruction of a Copy value to release a resource. Unsafe code also qualifies the usual RAII guarantees. section 4.1.2 section 4.7

A moved value in a container

Consider `let status = String::from("Active"); let statuses = vec![status];`. The String owns allocated memory, and placing it in the Vec moves ownership into the container. When `statuses` leaves scope, the container's destruction also destroys its contents. This is why the original `status` is no longer a separate usable owner after the move. section 4.1.2

RAII is useful beyond heap memory:

  • Box and Vec manage allocated memory; Rc and Arc use destruction as part of reference counting. section 4.1.3
  • Ref and RefMut guard RefCell borrows; MutexGuard releases a mutex lock when destroyed. Read-write locks likewise return guards for read or write access. section 4.1.3
Listing 4.2 RAII in Rust with Mutex and Condvar
use std::sync::{Arc, Condvar, Mutex};
use std::thread;

fn main() {
    let outer = Arc::new(
        (Mutex::new(0), Condvar::new())    #1
    );
    let inner = outer.clone();

    thread::spawn(move || {
        let (mutex, cond_var) = &*inner;                 #2
        let mut guard = mutex.lock().unwrap();           #3
        *guard += 1;                                     #4
        println!("inner guard={guard}");
        cond_var.notify_one();                           #5
    });                                                 #6

    let (mutex, cond_var) = &*outer;
    let mut guard = mutex.lock().unwrap();               #7
    println!("outer before wait guard={guard}");
    while *guard == 0 {                                  #8
        guard = cond_var.wait(guard).unwrap();           #9
    }
    println!("outer after wait guard={guard}");
}

The threaded Mutex and Condvar example combines several lifetimes: Arc shares ownership, a MutexGuard holds the lock, and waiting passes that guard to Condvar. Follow where each guard and Arc value leaves scope to see which resource is released. section 4.1.3

Use RAII when a type should reliably own a resource and clean it up at destruction. For a custom container or other resource-owning type, Drop supplies that cleanup point; for locks and borrows, use the guards returned by the relevant APIs rather than managing release separately. section 4.1.3 section 4.7

How Idiomatic Rust covers it

How deep it goes
Explains scope, moves, destruction, and Drop, then traces standard-library resource guards through a threaded example.
Examples
Contrasts C leaks with C++ cleanup, moves a String into a Vec, and coordinates threads with Mutex and Condvar.
What it assumes
Assumes a working Rust context but teaches RAII through C and C++ examples that require no proficiency in either language.
What you can do after
Build it from scratch by implementing Drop for resource-owning types, or apply it via Rust's containers and synchronization guards.
How it connects
Connects RAII to ownership, move semantics, Drop, reference counting, interior mutability, mutexes, and condition variables.

Also explained in

Compare how 4 books explain resource acquisition is initialization →

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Idiomatic Rust. The section links point to the parts of the book it draws on.