Course contentsShow
← Rust
Lesson 474 of 1,9104. Lifetimes and Advanced OwnershipFree lesson

Strategic Use of Box

Identify when heap allocation is required versus when borrowing is sufficient.

In this lesson, you will learn how to distinguish between the performance benefits of stack-allocated values and the strategic necessity of Box<T> for heap allocation.

The Stack vs. The Heap

By default, Rust allocates variables on the stack. The stack is extremely fast because it operates with a fixed size known at compile-time. However, the stack has strict limitations: it cannot grow, and it cannot easily house types whose size is unknown until the program runs (like recursive data structures).

When we use Box<T>, we are explicitly moving a value from the stack to the heap. The stack variable now only holds a pointer to that heap-allocated data.

When to Borrow, When to Box

A common beginner mistake is using Box out of habit. In Rust, borrowing is almost always superior to boxing.

  • Use Borrowing (&T) when you simply need to access data that already lives elsewhere. Borrowing has zero allocation cost and zero overhead.
  • Use Box<T> only when:
    1. Recursive Types: You are defining a type like a linked list node where the size must be calculated indirectly to avoid infinite recursion.
    2. Large Data Movement: You want to transfer ownership of a massive struct without copying the entire memory block. Moving a Box only moves the pointer (a few bytes), not the data it points to.
    3. Trait Objects: You need to store different types that implement the same trait in a single collection (Vec<Box<dyn Trait>>), as the compiler needs a fixed-size pointer to accommodate varying underlying sizes.

Example

Consider a large struct that you need to pass through several functions:

struct HugeData([u8; 10000]);

// BAD: Moving this on the stack copies 10,000 bytes every time
fn process(data: HugeData) {}

// GOOD: Moving a Box only copies a pointer, leaving the data on the heap
fn process_efficiently(data: Box<HugeData>) {}

If you don’t need to transfer ownership or store a recursive structure, keep it on the stack or pass by reference. Using Box incurs a heap allocation cost and adds a layer of indirection, which can hurt cache locality if used excessively.

Key Takeaway: Use Box only when you must control lifetime indirection, allow recursive sizing, or move massive data without copying; otherwise, prefer stack allocation or borrowing.