Course contentsShow
← Rust
Lesson 278 of 1,9103. Borrowing and ReferencesFree lesson

Reference Counting for Cyclic Graphs

Implement complex data structures with safe reference management.

In this lesson, you will learn why reference counting alone fails to clean up cyclic data structures and how we use Weak pointers to break those cycles.

The Problem with Circles

We’ve previously used Rc<T> to allow multiple owners for a piece of data. Rust’s Rc counts how many references point to an allocation; when the count hits zero, the memory is freed.

However, imagine a "parent" node that holds an Rc to a "child," and that "child" holds an Rc back to the "parent." When the external handles to these nodes go out of scope, the reference counts will never drop to zero because each node is still being held alive by the other. This is a memory leak.

Breaking the Cycle with Weak

To solve this, we introduce std::rc::Weak. A Weak reference is a pointer that does not contribute to the "strong" reference count. It allows you to access the data if it still exists, but it doesn't "own" the data or keep it alive.

Think of it like a library book:

  • Strong Reference (Rc): You have checked the book out. The library won't get rid of it while you have it.
  • Weak Reference (Weak): You are looking at the catalog entry. You can see the book exists, but your "reference" doesn't force the library to keep the book on the shelf.
use std::rc::{Rc, Weak};
use std::cell::RefCell;

struct Node {
    parent: RefCell<Weak<Node>>,
    children: RefCell<Vec<Rc<Node>>>,
}

// When creating a child:
// 1. Create the child with an Rc.
// 2. Assign the parent to the child using a Weak reference.

When you need to use the data inside a Weak pointer, you must call .upgrade(). This returns an Option<Rc<T>>. If the original Rc was already dropped, upgrade() returns None, safely preventing you from accessing invalid memory. By using Weak for back-references (like a child pointing to a parent), you ensure that there is always a clear "downward" ownership flow that can eventually drop to zero.

Key Takeaway: To manage cyclic graphs safely in Rust, use Rc for parent-to-child ownership and Weak for back-references to prevent memory leaks.