tezvyn:

Rust's Rc<T>: Shared Ownership on a Single Thread

AI-drafted, machine-checkedSource: doc.rust-lang.orgadvanced

Rust's `Rc<T>` enables shared ownership within a single thread. Think of it as a counter on a heap-allocated resource: cloning an `Rc` increments the count, and the resource is freed only when the count hits zero. Use it for graph nodes with multiple owners.

WHY IT EXISTS Rust's strict ownership model—one variable owns a piece of data—is great for safety but limiting when multiple parts of a program legitimately need to share ownership of the same data. Rc<T> provides a way to have multiple owners of heap-allocated data in a controlled, single-threaded context.

THE MENTAL MODEL Think of Rc<T> as giving out multiple keys to the same house. The data is the house, allocated on the heap. Each Rc is a key. When you clone() an Rc, you're not building a new house; you're just making a copy of the key and handing it to a new owner. The system keeps a count of how many keys exist. When the last key is destroyed (the Rc goes out of scope), the house is demolished (the data is deallocated).

HOW IT WORKS Rc<T> is a smart pointer that wraps your data T and stores it on the heap. Alongside the data, it maintains a reference count. Calling Rc::clone(&my_rc) creates a new pointer to the same data and increments this count. This is a fast, cheap operation. When an Rc instance is dropped, the count is decremented. If the count reaches zero, the inner value is dropped. By default, the data inside an Rc is immutable. To mutate it, you must wrap the data in a type that allows interior mutability, like Cell<T> or RefCell<T>.

WHEN TO USE IT Use Rc<T> when you need to share ownership of data and you can't determine a single owner at compile time, but you know the sharing will only happen on one thread. This is common in data structures like graphs or trees, where a single node might be referenced by multiple other nodes.

WHEN NOT TO USE IT Never use Rc<T> to share data across threads. Its reference count is not atomic, which would lead to data races. For thread-safe shared ownership, use Arc<T> (Atomic Reference Counted). The other major pitfall is creating reference cycles. If object A holds an Rc to B, and B holds an Rc back to A, their reference counts will never reach zero, causing a memory leak.

ONE CANONICAL EXAMPLE To prevent memory leaks from cycles, Rc<T> is often paired with Weak<T>. In a tree, a parent node might hold Rc<T> pointers to its children, expressing strong ownership. The children can hold Weak<T> pointers back to the parent. A Weak pointer doesn't increase the reference count and doesn't keep the data alive. It can be temporarily upgrade()d to an Rc<T> to safely access the parent, but this will return None if the parent has already been deallocated.

Read the original → doc.rust-lang.org

Get five bites like this every day.

Tezvyn delivers a daily feed of 60-second tech bites with quizzes to lock in what you learn.