Rc Type

Dear Computer

Chapter 11: Managing Memory

Rc Type

Suppose we have a dictionary of user settings in our program, and multiple components need to consult it throughout their lifetimes. No component can be considered the owner of the settings, so we lend out references:

Rust
fn load_preferences(components: &Vec<Component>) {
  let settings = Settings::load();
  for component in components {
    component.configure(&settings);
  }
}

But there's a problem here. If a component hangs on to the dictionary, its reference will outlive the owner. The compiler rejects this code because the lifetime of owner settings ends when the function returns but the components continue on.

Rust's single ownership model is not a good fit for a shared value that has no clear owner. The fix is to turn off single ownership for the value. But if we turn it off, we need some other mechanism for identifying garbage and reclaiming memory. We fall back on reference-counted garbage collection with the Rc abstraction, which wraps a value up with a reference counter.

We create an Rc for a shared but not singly-owned value by calling the associated function Rc::new. Its reference count is initially set to 1. The clone method creates an additional reference that points at the shared value and increments the count by 1. When a reference goes out of scope, the counter is automatically decremented. When the counter reaches 0, the memory is freed.

This code creates a shared value of 91 and prints the reference count, which is exposed through the strong_count method:

Rust
let outer;
{
  let inner = Rc::new(91);
  outer = inner.clone();
  println!("{}", Rc::strong_count(&outer));  // prints 2
}
println!("{}", Rc::strong_count(&outer));    // prints 1

The shared value's reference count is 2 when both Rc instances are in scope. It drops to 1 when inner goes out of scope.

This code creates a new Rc for the settings and passes clones to the components:

Rust
use std::rc::Rc;

fn load_preferences(components: &Vec<Component>) {
  let settings = Rc::new(Settings::load());
  for component in components {
    component.configure(settings.clone());
  }
}

The Rc class is especially useful for doubly-linked lists and graphs. The nodes of these abstractions are pointed to by multiple other nodes, making singular ownership a poor fit.

← Box TypeClosures →