Smart Pointers (Box, Rc, RefCell)
Rust is a systems programming language focused on speed, memory safety, and fearless concurrency — and smart pointers give you heap allocation, shared ownership, and interior mutability while keeping those guarantees.
Learn Smart Pointers (Box, Rc, RefCell) in our free Rust course — a beginner-friendly interactive lesson with worked examples, a practice exercise and a…
Part of the free Rust course at LearnCodingFast — hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.
In this lesson you'll meet Box for heap data and recursion, Rc for shared ownership, and RefCell for interior mutability.
What You'll Learn in This Lesson
1️⃣ Box: Heap Allocation and Recursion
Box<T> is the simplest smart pointer: it puts a value on the heap and owns it. You access the value just like a reference thanks to auto-dereferencing. Its standout use is enabling recursive types — without the indirection a Box provides, a type that contains itself would have infinite size.
The Cons list could only be defined because each link's tail is a Box<List> — a fixed-size pointer — rather than another List inline.
2️⃣ Rc and RefCell: Sharing and Interior Mutability
Rc<T> (reference counted) lets several owners share the same data; cloning bumps a count rather than copying. RefCell<T> moves borrow checking to runtime , letting you mutate data through a shared reference. Combined as Rc<RefCell<T>> , you get shared and mutable data.
Both log and log2 pointed at the same vector, so a push through either was visible through both. That's the power — and the responsibility — of shared mutable state.
Your turn. Fill in the blanks marked ___ , then run it.
Combine Rc and RefCell to share and mutate a counter through two handles. Run it with cargo run .
📋 Quick Reference — Smart Pointers
Practice quiz
Where does Box<T> store its value?
- On the stack
- In a register
- On the heap
- In static memory
Answer: On the heap. Box<T> allocates its value on the heap behind a single owner.
Why is Box needed for a recursive type like a Cons list?
- Without indirection the type would have infinite size
- For speed
- To enable cloning
- To allow threads
Answer: Without indirection the type would have infinite size. Box gives a fixed-size pointer so the recursive type's size is known.
What does Rc stand for?
- Raw cell
- Recursive container
- Read copy
- Reference counted
Answer: Reference counted. Rc is a reference-counted smart pointer allowing multiple owners.
What does Rc::clone(&shared) do?
- Deep-copies the data
- Increments the reference count
- Moves ownership
- Frees the data
Answer: Increments the reference count. Rc::clone bumps the owner count rather than copying the data.
After two Rc::clone calls on a fresh Rc, what is the strong_count?
- 3
- 1
- 2
- 0
Answer: 3. The original plus two clones gives a strong_count of 3.
What does RefCell<T> provide?
- Thread safety
- Compile-time-only checks
- Interior mutability with runtime borrow checks
- Heap allocation
Answer: Interior mutability with runtime borrow checks. RefCell allows mutation through a shared reference, checked at runtime.
Is Rc<T> thread-safe?
- Yes
- No, it is single-threaded; use Arc across threads
- Only with RefCell
- Only on the heap
Answer: No, it is single-threaded; use Arc across threads. Rc is single-threaded; Arc is the thread-safe atomic counterpart.
What does *counter.borrow_mut() += 1 do on a RefCell?
- Reads the value
- Clones the cell
- Panics always
- Mutably borrows and increments it
Answer: Mutably borrows and increments it. borrow_mut takes a mutable runtime borrow so you can change the value.
What is the classic combo for shared, mutable, single-threaded state?
- Box<Rc<T>>
- Rc<RefCell<T>>
- Arc<Mutex<T>>
- Vec<Box<T>>
Answer: Rc<RefCell<T>>. Rc<RefCell<T>> gives shared ownership plus interior mutability.
What runtime error happens with two overlapping mutable RefCell borrows?
- A compile error
- Silent corruption
- BorrowMutError panic
- Nothing
Answer: BorrowMutError panic. RefCell enforces borrow rules at runtime, panicking with BorrowMutError.