Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

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. Essentially a wrapper around a raw pointer with automatic deallocation (Drop). Minimal overhead for access. Essential for recursive types, trait objects, and controlling data placement.
  • Rc<T>: Single-threaded reference counting for shared ownership. Stores the value and counts on the heap. Rc::clone is cheap (increments count). Provides immutable access only. Not thread-safe.
  • Arc<T>: Thread-safe (atomic) reference counting for shared ownership. Stores the value and atomic counts on the heap. Use Arc::clone to share across threads. Provides immutable access only. Use with Mutex or RwLock for shared mutable state.
  • Interior Mutability (Cell<T>, RefCell<T>, OnceCell<T>): Allow mutating data through shared references (&T) within a single thread. Cell is for Copy types (no runtime checks, simple get/set). RefCell uses runtime borrow checks (panics on violation) for non-Copy types or when references are needed. 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 via locking.
  • Weak<T>: Non-owning pointer derived from Rc<T> or Arc<T>. Does not keep data alive (doesn’t affect strong count). Used to observe data or, critically, to break reference cycles and prevent memory leaks. Access requires upgrade() which returns an Option<Rc<T>> or Option<Arc<T>>.

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 (or combination) for the specific ownership, mutability, and concurrency requirements is key to writing idiomatic and robust Rust code.