Code Example Template
let pointer = Rc::new(5);
let clone = Rc::clone(&pointer);

Deep-Dive System Documentation

Single-Threaded Shared Ownership

In standard Rust, a value has exactly one owner. However, there are scenarios (like graph structures, trees, or shared state) where multiple references need read-only access to a single heap allocation. Rc<T> (Reference Counted) solves this by keeping track of the number of clones referencing the same memory block.

How It Works Under the Hood

When you allocate a value inside Rc<T>, Rust places the value on the heap along with two counters:

  1. Strong Count: The number of active owners. When this falls to 0, the value is safely dropped.
  2. Weak Count: The number of non-owning references (Weak<T>), used to prevent cycle memory leaks.
use std::rc::Rc;

// Heap allocation occurs here
let parent = Rc::new(String::from("Shared Node")); 
println!("Strong count: {}", Rc::strong_count(&parent)); // 1

{
    // Clone increments the strong counter (no heap allocation copy occurs)
    let child = Rc::clone(&parent); 
    println!("Strong count: {}", Rc::strong_count(&parent)); // 2
    println!("Shared content: {}", child);
} // child falls out of scope -> decrements count

println!("Strong count: {}", Rc::strong_count(&parent)); // 1

Shared Mutability Bypass

Rc<T> is strictly read-only (immutable). If you need shared mutability in a single-threaded environment, you must combine Rc<T> with interior mutability containers like RefCell<T>:

use std::rc::Rc;
use std::cell::RefCell;

let shared_data = Rc::new(RefCell::new(5));
*shared_data.borrow_mut() += 10; // bypasses compiler borrow check safely!

Cycle Memory Leaks

If two Rc pointers reference each other directly or via a chain, the strong count never hits 0, creating a memory leak.

  • Fix: Use Rc::downgrade(&rc) to create a Weak<T> pointer, which increments the weak counter instead of the strong counter.

Thread Safety Limits

Rc<T> is not thread-safe because it increments/decrements its counters using fast, non-atomic CPU operations. If you attempt to send an Rc<T> to another thread, the compiler will refuse to build, flagging a violation of the Send and Sync traits. For multi-threaded sharing, use Arc<T>.


Useful Methods

Rc::new(value: T) -> Rc<T>

Constructs a new Rc<T> on the heap, wrapping the given value and initializing strong/weak counters.

use std::rc::Rc;
let five = Rc::new(5);

Rc::clone(this: &Rc<T>) -> Rc<T>

Increments the strong reference count of the Rc pointer. Returns a clone pointing to the same heap allocation. This is $O(1)$ and avoids copying the inner value.

use std::rc::Rc;
let val = Rc::new(10);
let shared = Rc::clone(&val); // Reference count is now 2

Rc::strong_count(this: &Rc<T>) -> usize

Returns the number of strong references pointing to this allocation.

use std::rc::Rc;
let data = Rc::new("content");
assert_eq!(Rc::strong_count(&data), 1);
let cloned = Rc::clone(&data);
assert_eq!(Rc::strong_count(&data), 2);

Quick Reference Guide

use std::rc::Rc;
let data = Rc::new(vec![1, 2]);
let shared_ref = Rc::clone(&data);
let strong_count = Rc::strong_count(&data);