19.4 Box<T>
: The Simplest Smart Pointer
Box<T>
is often a newcomer’s first encounter with Rust smart pointers. Calling Box::new(value)
allocates value
on the heap and returns a box (stored on the stack) pointing to it. The Box<T>
owns that heap-allocated data and automatically frees it when the box goes out of scope.
19.4.1 Key Features of Box<T>
-
Pointer Layout
Box<T>
is essentially a single pointer to heap data, with no reference counting or extra metadata (aside from the pointer itself). -
Ownership Guarantees
The box cannot be null or invalid in safe Rust. Freeing the memory happens automatically when the box is dropped. -
Deref
Trait
Box<T>
implementsDeref
, making it largely transparent to use—*box
behaves like the underlying value, and you can often treat aBox<T>
as if it were a regular reference.
19.4.2 Use Cases and Trade-Offs
Common Use Cases:
-
Recursive Data Structures
A type that refers to itself (e.g., a linked list node) often needs a pointer-based approach.Box<T>
helps break the compiler’s requirement to know the exact size of types at compile time. -
Trait Objects
Dynamic dispatch via trait objects (dyn Trait
) requires an indirection layer, andBox<dyn Trait>
is a typical way to store such objects. -
Reducing Stack Usage
Large data can be placed on the heap to avoid excessive stack usage—particularly important in deeply recursive functions or resource-constrained environments. -
Efficient Moves
Moving aBox<T>
only copies the pointer, not the entire data on the heap. -
Optimizing Memory in Enums
Storing large data in an enum variant can bloat the entire enum type. Boxing that large data keeps the enum itself smaller.
Trade-Offs:
-
Indirection Overhead
Accessing heap-allocated data is inherently slower than stack access due to pointer dereferencing and possible cache misses. -
Allocation Costs
Allocating and freeing heap memory is usually more expensive than using the stack.
Example:
fn main() { let val = 5; let b = Box::new(val); println!("b = {}", b); // Deref lets us use `b` almost like a reference } // `b` is dropped, automatically freeing the heap allocation
Note: Advanced use cases may involve pinned pointers (Pin<Box<T>>
), but those are beyond this chapter’s scope.