Box<T>
Box<T> is the fundamental single-owner smart pointer in the Rust standard library. It allocates a value of type T on the heap while storing a single non-null pointer (Unique<T>) on the stack. When the Box<T> goes out of scope, its Drop implementation drops the inner T and deallocates the heap memory block.
Memory Representation
For any Sized type T, Box<T> has the exact same size and alignment as &T or *mut T (8 bytes on 64-bit targets) and carries zero runtime overhead beyond the heap allocation itself. Because its internal pointer is guaranteed never to be null, Option<Box<T>> uses niche optimization and also occupies 8 bytes.
Stack (8 bytes) Heap (size_of::<T>() bytes)
+--------------------+ +---------------------------+
| b: Box<Point> | | Point |
| ptr: 0x600001790 +-------> | x: 10.5 (f64, 8 bytes) |
+--------------------+ | y: 20.0 (f64, 8 bytes) |
+---------------------------+
struct Point {
x: f64,
y: f64,
}
fn main() {
let boxed_point = Box::new(Point { x: 10.5, y: 20.0 });
println!("size of Point: {} bytes", size_of::<Point>());
println!("size of Box<Point>: {} bytes", size_of::<Box<Point>>());
println!("size of Option<Box<Point>>: {} bytes", size_of::<Option<Box<Point>>>());
println!("point: ({}, {})", boxed_point.x, boxed_point.y);
}
size of Point: 16 bytes
size of Box<Point>: 8 bytes
size of Option<Box<Point>>: 8 bytes
point: (10.5, 20)
Moving Out of a Box<T> via Dereference
Unlike other smart pointers, Box<T> has special compiler support for dereference move: applying the unary * operator to an owned Box<T> moves the inner value out of the heap allocation onto the stack and immediately frees the empty heap block.
fn main() {
let heap_text: Box<String> = Box::new(String::from("moved out of box"));
let stack_text: String = *heap_text;
println!("stack_text: {}", stack_text);
}
stack_text: moved out of box
Key Box<T> Associated Functions
| Function / Method | Signature | Behavior |
|---|---|---|
Box::new(val) |
fn new(x: T) -> Box<T> |
Allocates heap memory and moves x into it |
Box::into_raw(b) |
fn into_raw(b: Box<T>) -> *mut T |
Consumes the Box and returns a raw pointer without dropping or deallocating T |
Box::from_raw(ptr) |
unsafe fn from_raw(raw: *mut T) -> Box<T> |
Reconstructs ownership of a Box<T> previously leaked via into_raw |
Box::leak(b) |
fn leak<'a>(b: Box<T>) -> &'a mut T |
Consumes the Box and returns a mutable reference 'a (often 'static) that lives for the rest of the program |
Box::into_pin(b) |
fn into_pin(boxed: Box<T>) -> Pin<Box<T>> |
Converts a Box<T> into a pinned heap allocation in place |
Controlled Leaking and Reclaiming with into_raw and from_raw
When passing ownership of a Rust heap object to a C library or storing it in an intrusive data structure, Box::into_raw suspends automatic destruction until Box::from_raw reclaims it:
fn main() {
let boxed = Box::new(vec![10, 20, 30]);
let raw_ptr: *mut Vec<i32> = Box::into_raw(boxed);
// Mutate through the raw pointer while Rust automatic drop is suspended:
unsafe {
(*raw_ptr).push(40);
}
// Reclaim ownership so the Vec and its Box allocation are properly freed:
let reclaimed: Box<Vec<i32>> = unsafe { Box::from_raw(raw_ptr) };
println!("reclaimed: {:?}", reclaimed);
}
reclaimed: [10, 20, 30, 40]