0Pricing
Learn Rust Coding · Lesson

Box, Rc, and Arc Smart Pointers

Understand how `Box` for heap allocation, `Rc` for shared ownership, and `Arc` for thread-safe shared ownership manage data.

Box, Rc, and Arc Smart Pointers is a free Learn Rust Coding lesson on CoddyKit — lesson 1 of 3. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the Learn Rust Coding learning path, one of 3 lessons in the course, and your progress syncs across the web and the CoddyKit app.

What are Smart Pointers?

Rust's ownership system is great for memory safety, but sometimes you need more flexibility. That's where smart pointers come in!

Smart pointers are data structures that act like pointers but also have additional metadata and capabilities. They manage memory, ownership, and other resources automatically.

Box: Storing Data on the Heap

The simplest smart pointer is Box<T>. It allows you to store data on the heap instead of the stack.

  • Stack: Fast, fixed-size data.
  • Heap: Slower, flexible-size data, allocated at runtime.

When you put a value in a Box, the Box itself is on the stack, but the data it points to lives on the heap.

Using Box for Heap Allocation

Let's see how Box moves data to the heap. This is useful for large data or when you don't know the size at compile time.

Run this code to observe a value being boxed.

fn main() {
  let x = 5; // x is on the stack
  let boxed_x = Box::new(x); // x's value is moved to the heap, boxed_x is on stack
  println!("Value on stack: {}", x);
  println!("Value in Box (on heap): {}", *boxed_x); // Dereference to get value
}

When Box is Useful

You might use Box<T> in these situations:

  • When you have a type whose size can't be known at compile time, and you need to store it somewhere with a known, fixed size.
  • When you have a large amount of data and want to transfer ownership without copying the data itself.
  • When you want to own a trait object (e.g., Box<dyn Trait>).

Rc: Multiple Owners (Single Thread)

Rust's ownership rules mean a value usually has only one owner. But what if multiple parts of your program need to "own" the same data?

Rc<T>, or Reference Counted, allows multiple owners of data in a single-threaded scenario. It keeps track of how many references point to the data.

When the count drops to zero, the data is cleaned up.

Sharing Data with Rc

Rc::clone() increments the reference count. This isn't a deep copy; it just creates another pointer to the same data.

Notice how the data is shared, and its value is accessible from different "owners".

use std::rc::Rc;

fn main() {
  let value = Rc::new(String::from("Shared String"));
  println!("Count after creation: {}", Rc::strong_count(&value));

  let value_clone_a = Rc::clone(&value); // Increment count
  println!("Count after clone A: {}", Rc::strong_count(&value));

  {
    let value_clone_b = Rc::clone(&value); // Increment count
    println!("Count after clone B: {}", Rc::strong_count(&value));
    println!("Data from A: {}", value_clone_a);
    println!("Data from B: {}", value_clone_b);
  } // value_clone_b goes out of scope, count decreases

  println!("Count after B goes out of scope: {}", Rc::strong_count(&value));
}

Arc: Shared Ownership (Multi-Thread)

Rc<T> works well for single-threaded applications. However, if you need to share data between multiple threads, Rc<T> is not safe.

Arc<T>, or Atomic Reference Counted, is the thread-safe version of Rc<T>. It uses atomic operations to update the reference count, ensuring safety across threads.

Arc has a slight performance overhead compared to Rc due to atomic operations.

Sharing Data Across Threads with Arc

This example shows how Arc allows multiple threads to safely access and read the same shared data. Each thread gets its own `Arc` clone.

The main thread waits for all spawned threads to complete.

use std::sync::Arc;
use std::thread;

fn main() {
  let data = Arc::new(vec![1, 2, 3, 4, 5]);
  let mut handles = vec![];

  for i in 0..3 {
    let data_clone = Arc::clone(&data); // Clone Arc for each thread
    let handle = thread::spawn(move || {
      println!("Thread {} has data: {:?}", i, *data_clone);
    });
    handles.push(handle);
  }

  for handle in handles {
    handle.join().unwrap();
  }
  println!("All threads finished.");
}

Box, Rc, or Arc?

Choosing the right smart pointer depends on your needs:

  • Box<T>: When you need to put data on the heap, typically for single ownership or when dealing with recursive types.
  • Rc<T>: When you need multiple owners for data in a single-threaded context.
  • Arc<T>: When you need multiple owners for data in a multi-threaded (concurrent) context.

Always prefer Box or Rc if you don't need thread safety, as Arc has a performance cost.

Smart Pointer Check

You need to store a large image file on the heap, and only one part of your program will own and manage it. Which smart pointer should you use?

Recap: Smart Pointers

In this lesson, you learned about three fundamental Rust smart pointers:

  • Box<T>: For allocating data on the heap with single ownership.
  • Rc<T>: For enabling multiple owners of data in a single-threaded environment.
  • Arc<T>: For enabling multiple, thread-safe owners of data in a multi-threaded environment.

These smart pointers give you more control over memory management while still leveraging Rust's safety guarantees.

Frequently asked questions

Is the “Box, Rc, and Arc Smart Pointers” lesson free?

Yes — the full text of “Box, Rc, and Arc Smart Pointers” is free to read here on the web, and the Learn Rust Coding course includes 3 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the Learn Rust Coding course, upgrade to CoddyKit PRO.

What will I learn in “Box, Rc, and Arc Smart Pointers”?

Understand how `Box` for heap allocation, `Rc` for shared ownership, and `Arc` for thread-safe shared ownership manage data. You practise Learn Rust Coding with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.

Do I need any experience to start Learn Rust Coding?

No prior experience is required. Learn Rust Coding on CoddyKit is structured for beginners through advanced learners; this is — lesson 1 of 3, so you can start here or from the beginning and move at your own pace.

How long does the “Box, Rc, and Arc Smart Pointers” lesson take?

Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.

Can I write and run code in this Learn Rust Coding lesson?

Yes. Every Learn Rust Coding lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.

All lessons in this course

  1. Box, Rc, and Arc Smart Pointers
  2. Interior Mutability: RefCell, Cell
  3. Fearless Concurrency with Threads
← Back to Learn Rust Coding