Rc

  • Reference Counted Smart Pointer is denoted by the symbol Rc<T>.
  • A value can be cleaned up if there are zero references to it, which is what happens when the Rc<T> smart pointer counts references to a value to determine whether it is still in use.
  • One threaded reference-counting pointer is the Rc<T> smart pointer.

Using Rc to share data

First, let’s make the two lists that are jointly owned by a third list.

Rust Rc<T> -

The two lists in the accompanying graphic, b and c, share ownership of the third list, a.

Let’s implement the above scenario using Box<T> type.

				
					 enum List   
{  
  Cons(i32, Box<List>),  
  Nil,  
}  
use List::{Cons,Nil};  
fn main()  
{  
  let a = Cons(10, Box::new(Cons(15,Box::new(Nil))));  
  let b = Cons(2, Box::new(a));  
  let c = Cons(1, Box::new(a));   
} 
				
			

Output:

Rust Rc<T> -

The cons variant in the example above consists of Box<T> referring to a list and data of type i32. The ownership of ‘a’ is transferred to the ‘b’ list when we create it. The ‘a’ list is then attempted to be moved to the ‘c’ list, however this is unsuccessful because the ‘a’ list has already been moved to the ‘b’ list.

How to overcome this problem

By modifying the cons variant’s definition, we can solve this issue. The cons variant now has Rc<T> pointing to the List and data that they own.

Example:

				
					enum List   
{  
  Cons(i32, Rc<List>),  
  Nil,  
}  
use List::{Cons,Nil};  
use std::rc::Rc;  
fn main()  
{  
  let a = Rc::new(Cons(10, Rc::new(Cons(15,Rc::new(Nil)))));  
  let b = Cons(2, Rc::clone(&a));  
  let c = Cons(1, Rc::clone(&a));   
}  
				
			

To include the Rc<T> in the scope, we must include the use statement in the example above. As a and b are now sharing possession of the data in that Rc<List>, we will clone the Rc<T> list that an is holding in place of assuming ownership of it. This will increase the number of references from one to two. When we create the c List, we will clone the Rc<List> once more, which will increase the references from two to three.

Cloning an Rc Increases the Reference Count

We will now examine how Rc<T> modifies the reference count when the list leaves its scope.

Example:

				
					 enum List   
{  
  Cons(i32, Rc<List>),  
  Nil,  
}  
use List::{Cons,Nil};  
use std::rc::Rc;  
fn main()  
{  
  let a = Rc::new(Cons(10, Rc::new(Cons(15,Rc::new(Nil)))));  
  println!("Reference count after creating a List : {}", Rc::strong_count(&a));  
  let b = Cons(2, Rc::clone(&a));  
  println!("Reference count after creating b List : {}", Rc::strong_count(&a));  
  {  
  let c = Cons(1, Rc::clone(&a));   
  println!("Reference count after creating c List : {}",Rc::strong_count(&a));  
  }  
  println!("Reference count when c goes out of the scope : {}",Rc::strong_count(&a));  
}  
				
			

Output:

				
					Reference count after creating a List : 1
Reference count after creating b List : 2
Reference count after creating c List : 3
Reference count when c goes out of the scope : 2
				
			

In the example above, we use the Rc::strong_count function to output the reference count. A in Rc<List> has an initial reference count of 1, and this reference count rises by 1 upon calling clone. The reference count drops by one if the variable leaves the scope. As a result, when a Rc<T>/ value exits the scope, the Drop trait automatically reduces the reference count.

Share this Doc

Rust Rc<T>

Or copy link

Explore Topic