C.W.K.
Stream
Lesson 03 of 05 · published

Rc — Shared Ownership

~11 min · smart-pointers, rc, shared-ownership

Level 0Rust Curious
0 XP0/80 lessons0/19 achievements
0/100 XP to next level100 XP to go0% complete

Box has a single owner. But sometimes a value genuinely needs multiple owners — a node referenced from several places, shared config read by many parts. Rc<T> (reference counted) makes that safe.

Shared ownership by counting

Rc<T> keeps a count of how many owners exist. Rc::clone doesn't copy the data — it bumps the count and hands out another handle to the same value. When each owner drops its Rc, the count drops; when it hits zero, the value is freed. Multiple owners, exactly one deallocation, all automatic.

Rc::clone is cheap

Rc::clone(&x) is the idiomatic spelling (rather than x.clone()) precisely because it signals 'this is a cheap refcount bump, not a deep copy.' It copies a pointer and increments a counter — nothing more. Reading Rc::clone tells the reader 'shared ownership here,' which a bare .clone() would hide.

Rc is for multiple owners in a single thread. Use it when one value must outlive any single owner because several parts of your program need it. The count tracks them; the last one out frees the value. (For sharing across threads, you need Arc — coming two lessons from now.)

The catch: Rc is read-only

Rc<T> gives you shared, immutable access. You can't get a &mut through it, because multiple owners plus mutation would violate aliasing XOR mutation. To mutate shared data, you pair Rc with RefCell — which is exactly the next lesson, and the reason interior mutability exists.

Code

Rc: several owners, one deallocation·rust
use std::rc::Rc;

struct Config { name: String }

fn main() {
    let shared = Rc::new(Config { name: "app".into() });
    println!("owners: {}", Rc::strong_count(&shared)); // 1

    let a = Rc::clone(&shared); // cheap: bumps count, same underlying data
    let b = Rc::clone(&shared);
    println!("owners: {}", Rc::strong_count(&shared)); // 3
    println!("{} {}", a.name, b.name);
} // a, b, shared all drop -> count reaches 0 -> Config freed once

External links

Exercise

Model two Owners sharing one Resource via Rc. Print Rc::strong_count after each clone and after owners drop (use inner scopes to drop them early). Confirm the count rises and falls. Why is Rc::clone preferred over .clone() here stylistically?
Hint
Rc::clone makes it explicit that you're sharing ownership cheaply (a refcount bump), not deep-copying the data. .clone() would compile but obscure the intent — readers couldn't tell a cheap Rc clone from an expensive deep clone.

Progress

Progress is local-only — sign in to sync across devices.
Spotted a bug or have feedback on this page?Report an Issue

Comments 0

🔔 Reply notifications (sign in)
Sign inPlease sign in to comment.

No comments yet — be the first.