19.9 Summary

Rust’s standard library provides a versatile set of smart pointers that extend its core ownership and borrowing system to handle more complex memory management scenarios safely and efficiently:

  • Box<T>: Simple heap allocation with exclusive ownership. Essential for recursive types, trait objects, and controlling data placement.
  • Rc<T>: Single-threaded reference counting for shared ownership of immutable data. Clones are cheap, increments count. Not thread-safe.
  • Arc<T>: Thread-safe (atomic) reference counting for shared ownership of immutable data across threads. Use Arc::clone to share.
  • Interior Mutability (Cell<T>, RefCell<T>, OnceCell<T>): Allow mutating data through shared references within a single thread. Cell is for Copy types (no runtime checks). RefCell uses runtime borrow checks (panics on violation). OnceCell handles write-once initialization. Often combined with Rc<T> (e.g., Rc<RefCell<T>>).
  • Thread-Safe Mutability (Mutex<T>, RwLock<T>): Used with Arc<T> (e.g., Arc<Mutex<T>>) to allow safe mutation of shared data across multiple threads by ensuring exclusive (Mutex) or shared-read/exclusive-write (RwLock) access.
  • Weak<T>: Non-owning pointer derived from Rc<T> or Arc<T>. Does not keep data alive. Used to observe data or, critically, to break reference cycles and prevent memory leaks. Access requires upgrade().

These tools enable developers to implement complex data structures, manage shared state, and build concurrent applications without sacrificing Rust’s core promise of memory safety. They replace the need for manual memory management found in C and mitigate issues sometimes encountered with C++ smart pointers (like dangling raw pointers or undetected cycles) by integrating deeply with the borrow checker and employing runtime checks or atomic operations where necessary. Choosing the right smart pointer for the specific ownership and concurrency requirements is key to writing idiomatic and robust Rust code.