19.8 Weak<T>: Non-Owning References

Rc<T> and Arc<T> enable shared ownership through reference counting. However, they can create reference cycles if two or more owners reference each other. Such cycles prevent the reference count from reaching zero, causing memory leaks.

Weak<T> provides a non-owning reference that does not increment the strong count. This breaks cycles, ensuring that memory can be freed when no strong owners remain.

19.8.1 Strong and Weak References

  • Strong References (Rc<T> or Arc<T>): Contribute to the strong count. The data is dropped when the strong count reaches zero.
  • Weak References (Weak<T>): Do not affect the strong count. They point to the data but don’t keep it alive. If all strong references are dropped, upgrading a Weak<T> will return None since the data no longer exists.

19.8.2 Preventing Cycles

Weak<T> is particularly useful in graph or tree-like structures that might otherwise form cycles. By using a weak reference for the parent link, you ensure that nodes do not keep each other alive indefinitely.

Example:

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

#[derive(Debug)]
struct Node {
    value: i32,
    parent: RefCell<Option<Weak<RefCell<Node>>>>,
    children: RefCell<Vec<Rc<RefCell<Node>>>>,
}

fn main() {
    let parent = Rc::new(RefCell::new(Node {
        value: 1,
        parent: RefCell::new(None),
        children: RefCell::new(vec![]),
    }));
    let child = Rc::new(RefCell::new(Node {
        value: 2,
        parent: RefCell::new(Some(Rc::downgrade(&parent))),
        children: RefCell::new(vec![]),
    }));
    parent
        .borrow_mut()
        .children
        .borrow_mut()
        .push(Rc::clone(&child));
    println!("Parent: {:?}", parent);
    println!("Child: {:?}", child);
    // No cycle keeps them alive indefinitely, as the child uses a Weak ref. to the parent.
}

19.8.3 Upgrading a Weak Reference

A Weak<T> can be "upgraded" to an Rc<T> or Arc<T> via upgrade(). If the data is still alive, upgrade() returns Some(Rc<T>) or Some(Arc<T>). If not, it returns None.