rust / intermediate
Snippet
Smart Pointer Cycles with Rc and RefCell
Rc (Reference Counting) allows multiple ownership, but cycles cause memory leaks. Using Weak references breaks cycles - a Weak does not increment the strong count. The upgrade() method converts Weak back to Option<Rc>. In this tree structure, parent holds a Weak reference to avoid retaining children, while children hold strong Rc references to their parent. Rc::downgrade creates a Weak from an Rc, and the borrow checker ensures no reference cycles exist at compile time for non-cell types.
snippet.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
use std::cell::RefCell;use std::rc::{Rc, Weak};#[derive(Debug)]struct Node {value: i32,children: RefCell<Vec<Rc<Node>>>,parent: RefCell<Weak<Node>>,}impl Node {fn new(value: i32) -> Rc<Self> {Rc::new(Node {value,children: RefCell::new(Vec::new()),parent: RefCell::new(Weak::new()),})}fn add_child(&self, child: Rc<Node>) {self.children.borrow_mut().push(Rc::clone(&child));*child.parent.borrow_mut() = Rc::downgrade(self);}fn get_parent(&self) -> Option<Rc<Node>> {self.parent.borrow().upgrade()}}fn main() {let leaf = Node::new(3);let branch = Node::new(5);branch.add_child(Rc::clone(&leaf));println!("Leaf parent: {:?}", leaf.get_parent());println!("Branch strong count: {}", Rc::strong_count(&branch));println!("Leaf strong count: {}", Rc::strong_count(&leaf));}
Breakdown
1
parent: RefCell<Weak<Node>>
Weak does not prevent Node from being dropped; prevents strong cycles
2
Rc::downgrade(self)
Creates a Weak pointer to the Rc; does not increment reference count
3
child.parent.borrow_mut() = Rc::downgrade(self);
Sets child's parent weak reference back to this node
4
self.parent.borrow().upgrade()
Converts Weak to Option<Rc>; None if parent was dropped