Skip to content
CryoCryo home
Stdliballoc

rc

import std::alloc::rc; — in the prelude · source

Rc<T, A>

type struct Rc<T, A = GlobalAlloc> {
    inner: RcInner<T, A>*;

    static new(value: T) -> Rc<T, GlobalAlloc>;
    static new_in(value: T, alloc: A) -> Rc<T, A>;
    static try_new(value: T) -> Result<Rc<T, GlobalAlloc>, AllocError>;
    static try_new_in(value: T, alloc: A) -> Result<Rc<T, A>, AllocError>;
    clone(&this) -> Rc<T, A>;
    downgrade(&this) -> Weak<T, A>;
    strong_count(&this) -> u64;
    weak_count(&this) -> u64;
    as_ptr(&this) -> T*;
    get_ref(&this) -> T*;
    get_mut(mut &this) -> Option<T*>;
}

Shared ownership within one thread. Rc shares ownership of a heap value among many holders. The value lives until the last strong handle drops, at which point T::drop() runs; the storage comes back once the last weak handle is gone too.

Rc is not thread-safe. The counts are plain u64s with no synchronization. Sending one across threads, or cloning it from two threads at once, is a data race — use Arc.

MethodNotes
new(value) / new_inPanics on allocation failure.
try_new / try_new_inThe fallible forms.
cloneAnother handle to the same value; bumps the strong count.
downgradeA Weak<T, A>; bumps the weak count only.
get_refT* — shared borrow, sound for reads while any clone is alive.
get_mutOption<T*>Some only when this is the sole owner.
strong_count / weak_countu64, advisory.

get_mut is the sound way to mutate an Rc-managed value. It hands back a pointer only when there is exactly one strong reference and no outstanding Weak — either could otherwise alias the value, a Weak by upgrading into a second strong handle.

Weak<T, A>

type struct Weak<T, A = GlobalAlloc> {
    inner: RcInner<T, A>*;

    static new() -> Weak<T, GlobalAlloc>;
    upgrade(&this) -> Option<Rc<T, A>>;
    clone(&this) -> Weak<T, A>;
    strong_count(&this) -> u64;
}

A Weak<T, A> does not keep the value alive. Once every strong handle is gone the value is dropped and upgrade returns None from then on. This is the tool for breaking reference cycles: hold the back-edge of a cycle as a Weak and it will not leak.

Weak::new() allocates nothing and never upgrades — useful as a placeholder before a cycle is wired up.

Why teardown has two phases

type struct RcInner<T, A> {
    strong: u64;
    weak:   u64;
    value:  T;
    alloc:  A;
}

The header carries two counts. strong tracks live Rc handles. weak tracks live Weak handles plus one shared unit owned by the strong group, so it never drops below 1 while any Rc exists.

When strong hits zero the value is dropped and the strong group releases its shared unit. When weak then hits zero — on that same drop, or later when the last surviving Weak goes away — the header is freed. That split is what lets a Weak safely outlive the value: the header, and the strong flag upgrade reads, stays mapped until no handle of either kind remains.

Trait implementations

implement<T, A> trait Drop for struct Rc<T, A>
where T: Drop, A: Allocator

implement<T, A> trait Drop for struct Weak<T, A>
where T: Drop, A: Allocator

clone is an inherent method rather than a Clone impl, so generic code that wants T: Clone on the pointee is not confused by a cheap handle copy.