When to use Rc vs Box?

Rc provides shared ownership so by default its contents can't be mutated, while Box provides exclusive ownership and thus mutation is allowed:

use std::rc::Rc;

fn main() {
    let mut a = Box::new(1);
    let mut b = Rc::new(1);

    *a = 2; // works
    *b = 2; // doesn't
}

In addition Rc cannot be sent between threads, because it doesn't implement Send.

The bottom line is they are meant for different things: if you don't need shared access, use Box; otherwise, use Rc (or Arc for multi-threaded shared usage) and keep in mind you will be needing Cell or RefCell for internal mutability.


Looking at the example given in the description, I think the real question here is "when to use Rc versus &Box" (note the ampersand).

Both Rc and &Box store the underlying data on the heap, neither can be sent across threads, and both allow immutable sharing (demonstrated by the aforementioned example). However, the biggest difference is that Rc gives you a shared (immutable) owned value while with &Box you get a shared (immutable) reference.

In the Rc case, the underlying data will be dropped (freed/deallocated) whenever the last owner (whether the original one or any cloned one) gets dropped – that's the idea of reference counting. In the &Box case, however, there is only one owner: any shared references to it will become invalid immediately after the owner gets out of scope.

Said differently, contrary to a Rc::clone(), binding a variable to a new &Box (let a2 = &a; in the example) will not make it live any longer than it would otherwise.

As a concrete example, the following is valid:

use std::rc::Rc;

fn main() {
    let rc_clone;
    {
        let rc = Rc::new(1);
        rc_clone = rc.clone();
        // rc gets out of scope here but as a "shared owner", rc_clone
        // keeps the underlying data alive.
    }
    println!("{}", rc_clone);  // Ok.
}

But this isn't:

fn main() {
    let b_ref;
    {
        let b = Box::new(1);
        b_ref = &b;
        // b gets out of scope here and since it is the only owner,
        // the underlying data gets dropped.
    }
    println!("{}", b_ref); // Compilation error: `b` does not live long enough.
}