Course contentsShow
← Rust
Lesson 117 of 1,9102. The Ownership ModelFree lesson

Weak References

Implement circular data structures without creating memory leaks.

In this lesson, you will learn how to break "reference cycles" to prevent memory leaks when using multiple ownership.

The Problem: Reference Cycles

You have already learned about Rc<T> (Reference Counting), which allows multiple parts of your code to own the same data. However, Rc<T> has a dangerous weakness: if two objects point to each other, their reference counts will never drop to zero.

Imagine two nodes in a graph, Node A and Node B. If A owns a pointer to B, and B owns a pointer to A, both nodes are kept alive by the other. Even if your program stops using them, the memory is never cleaned up because the count stays at 1 for both. This is a memory leak.

The Solution: Weak References

A Weak<T> reference is a special pointer that points to data managed by an Rc<T>, but it does not contribute to the ownership count. Think of it as a "peek" at the data rather than a "claim" on the data.

Because a Weak<T> reference doesn't guarantee the data exists, it must be upgraded to an Rc<T> before you can use it. If the data has already been dropped, the upgrade will return None.

Breaking the Cycle

To fix circular structures, you designate one side of the relationship as "strong" (using Rc<T>) and the other as "weak" (using Weak<T>).

use std::rc::{Rc, Weak};

struct Node {
    next: Option<Rc<Node>>,
    parent: Option<Weak<Node>>, // Use Weak to prevent a cycle
}

By using Weak for the parent field, the parent doesn't "hold on" to the child in a way that prevents destruction. The child points to the parent, but the parent doesn't increment the child's reference count. When the original owner of the Rc drops the data, the reference count finally hits zero, allowing Rust to safely reclaim the memory.

Key Takeaway: Use Weak references for back-links or parent pointers to break circular dependencies and ensure your memory can be cleaned up correctly.