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. UseArc::clone
to share across threads. Provides immutable access only. Use withMutex
orRwLock
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 forCopy
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 withRc<T>
(e.g.,Rc<RefCell<T>>
). - Thread-Safe Mutability (
Mutex<T>
,RwLock<T>
): Used withArc<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 fromRc<T>
orArc<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 requiresupgrade()
which returns anOption<Rc<T>>
orOption<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.