Skip to content

Latest commit

 

History

History
107 lines (85 loc) · 2.81 KB

Rc.md

File metadata and controls

107 lines (85 loc) · 2.81 KB

Table of contents


URLs

Smart pointer URL
Rc std::rc::Rc

Declarations

RcBox<T>

#[repr(C)]
struct RcBox<T: ?Sized> {
    strong: Cell<usize>,
    weak: Cell<usize>,
    value: T,
}

Rc<T>

pub struct Rc<T, A = Global>
where
    A: Allocator,
    T: ?Sized,
{
    ptr: NonNull<RcBox<T>>,
    phantom: PhantomData<RcBox<T>>,
    alloc: A,
}

The Rc<T> type wraps the value of type T. The value of type T is allocated in the heap.


In a nutshell

The Rc stands for Reference Counted. The Rc<T> type is thread-unsafe reference-counting pointer. It uses non-atomic reference counting.
The Rc<T> type keeps track of the number of references to original value it wraps.
The Rc<T> type is useful when we can’t determine at compile time in which scope the value T will be destroyed.

To avoid names clashes with T's methods, all methods of Rc are associated functions and they must be called using fully qualified syntax, example: Rc::get_mut(...).

The Rc can't be sent between threads, therefore Rc<T> implements !Send and !Sync:

impl<T: ?Sized, A: Allocator> !Send for Rc<T, A> {}
impl<T: ?Sized, A: Allocator> !Sync for Rc<T, A> {}

Example

enum List {
    Cons(i32, Rc<List>),
    Nil,
}

use crate::List::{Cons, Nil};
use std::rc::Rc;

fn main() {
    let a = Rc::new(Cons(5, Rc::new(Cons(10, Rc::new(Nil)))));
    println!("count after creating a = {}", Rc::strong_count(&a));
    let b = Cons(3, Rc::clone(&a));
    println!("count after creating b = {}", Rc::strong_count(&a));
    {
        let c = Cons(4, Rc::clone(&a));
        println!("count after creating c = {}", Rc::strong_count(&a));
    }
    println!("count after c goes out of scope = {}", Rc::strong_count(&a));
}

Cloning

Rc's implementation of Clone trait may be called using fully qualified syntax or method-call syntax:

  • rc.clone();
  • Rc::clone(&rc);

The Rc::clone() doesn't clone original wrapped value of type T, instead it creates new instance of Rc<T> and increments the strong_count.
When instance of Rc goes out of scope it is destroyed and the strong_count is decremented by 1.
When the strong_count is reached 0 the original value of type T is also dropped.


Deref

The Rc implements Deref trait, so you can call T's methods on a value of type Rc<T>.