Skip to content
CryoCryo home
Stdliballoc

rc

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

Types

Rc<T, A>

type struct Rc<T, A = GlobalAlloc> where A: Allocator {
    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.

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.

Properties

PropertyType
innerRcInner<T, A>*

Constructors

static new(value: T) -> Rc<T, GlobalAlloc>;

Allocate a new Rc backed by GlobalAlloc with an initial count of 1. Panics if the allocator refuses the request; use try_new to handle OOM.

static new_in(value: T, alloc: A) -> Rc<T, A>;

Allocate with a caller-supplied allocator. Panics on allocation failure; use try_new_in for fallible construction.

static try_new(value: T) -> Result<Rc<T, GlobalAlloc>, AllocError>;

Fallible constructor backed by GlobalAlloc. Returns Err(AllocError) if the allocator refuses the request.

static try_new_in(value: T, alloc: A) -> Result<Rc<T, A>, AllocError>;

Fallible constructor with a caller-supplied allocator. The allocator instance is stored in the inner header and is used to free the inner when the last reference drops.

Methods

clone(&this) -> Rc<T, A>;

Produce another Rc pointing at the same value. Increments the strong count; the two handles are interchangeable. Allocator is shared through the inner pointer; no copy needed.

downgrade(&this) -> Weak<T, A>;

A non-owning Weak handle to the same value. Bumps the weak count but not the strong count, so it will not keep the value alive.

strong_count(&this) -> u64;

Current strong-reference count. Primarily useful for tests and assertions; acting on this value in a running program is rarely the right move.

weak_count(&this) -> u64;

Number of live Weak handles. The strong group's shared unit is excluded, so this is 0 when no Weak has been created.

as_ptr(&this) -> T*;

Raw pointer to the shared value. Valid for as long as any strong clone of this Rc is still alive; dereferencing after the last drop is undefined.

get_ref(&this) -> T*;

Shared borrow of the value. Sound for reads while any strong clone is alive. Prefer over as_ptr for the read path. Do NOT mutate through this when other clones exist - use get_mut, which is gated on uniqueness.

get_mut(mut &this) -> Option<T*>;

Mutable borrow of the value, but only when this is the sole owner: exactly one strong reference AND no outstanding Weak (either could otherwise alias the value - a Weak by upgrading to a second strong). Otherwise None. This is the sound way to mutate an Rc-managed value.

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.

Properties

PropertyType
innerRcInner<T, A>*

Constructors

static new() -> Weak<T, GlobalAlloc>;

A Weak that never upgrades. Allocates nothing; upgrade always returns None. Useful as a placeholder before a cycle is wired up.

Methods

upgrade(&this) -> Option<Rc<T, A>>;

Try to obtain a strong Rc. Returns None once the last strong reference has gone (the value has been dropped), or for a dangling Weak::new(). On success the strong count is bumped, so the returned Rc keeps the value alive.

clone(&this) -> Weak<T, A>;

Another Weak to the same value. Bumps the weak count.

strong_count(&this) -> u64;

Live strong count, or 0 for a dangling Weak. Advisory.

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.

Properties
PropertyType
strongu64
weaku64
valueT
allocA

Trait implementations

Rc

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

Weak

implement<T, A> trait Drop for struct Weak<T, A> where 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.