Play with Dynamic Memory using Smart Pointers in Rust [Part-2]

Reading Time: 4 minutes

Smart Pointers are the data structures that behave like a pointer while providing additional features such as memory management. Smart Pointers keep track of the memory that it points to, and are also used to manage other resources such as file handling and network connections.

Hello, folks!  your wait is over, here is the second blog of  Play with Dynamic memory using Smart pointers in Rust. I hope you have learned a lot from the first part. It’s better to go with the previous blog first to gain more understanding about Smart Pointers.
In Rust we have five Smart pointers:
=> Box<T>
=>
Deref<T>
=>
Drop trait
=>
RC<T>
=>
Refcell<T>
The first two Smart Pointers, we already discussed in our previous blog. Now, let’s understand the rest three Smart Pointers which are:

  • Drop trait.
  • RC<T>.
  • Refcell<T>

Drop trait:

  • When the instance goes out of scope, the drop trait can release the resources related to that instance.
  • It is used to deallocate the space on the heap that the Box trait points to.
  • The drop method will automatically call when the instance goes out of scope.
  • We can implement the drop method() in the drop trait to customize the behaviour of the drop trait.

For Example:

struct Employee
{  
  age : i32,  
 }  
impl Drop for Employee 
{  
  fn drop(&mut self)  
  {  
    println!("The instances of john and bill is dropped: {}", self.age);  
  }  
}  
fn main()  
{  
  let john = Employee{ age : 10};  
  let bill = Employee{ age: 20};  
  println!("The john and bill Instances are created.");  
}  

Output:

This image has an empty alt attribute; its file name is screenshot-18.png

In this example, we have overridden the drop method inside the drop trait and in the main function, we have created instances like ‘John’ and ‘bill’ of the type Employee and at the end of the main() function, when the instances will go out of the scope then drop method will call automatically.

RC<T>:

  • The Rc<T> stands for Reference Counted Smart Pointer.
  • Reference Counter continuously pointing to a value that is in use or if not, then memory related to that value will be cleaned up.
  • It is a single-threaded reference-counting pointer.

The workflow of RC<T>:

Here ‘b‘ and ‘c‘ share the ownership of ‘a‘ node.

This image has an empty alt attribute; its file name is rust-rc.png
Fig: 1 Workflow of RC<T>.

As we have seen that due to the ownership concept in Rust, we cannot share the ownership which multiple owners.

Instead of taking ownership of ‘a‘, we can clone the Rc<List> of ‘a’. When ‘b’ and ‘c’ will share the ownership of ‘a’, then the number of references will increase accordingly (one for each reference).

For Example:

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

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

pub fn reference_counter()
{
    let first = Rc::new(Cons(25, Rc::new(Cons(80,Rc::new(Nil)))));

    println!("Reference count after the first instance is created : {}", Rc::strong_count(&first));
    let second = Cons(2, Rc::clone(&first));
    println!("Reference count after cloned the second from first : {}", Rc::strong_count(&first));

    {
        let third = Cons(1, Rc::clone(&first));
        println!("Reference count inside the loop : {}", Rc::strong_count(&first));
    }
    println!("Reference count when the scope of third ended : {}",Rc::strong_count(&first));
}

In this example, we actually print the reference count from various scopes of the program by calling the Rc::strong_count function. Initially the reference count of a in Rc<List> is 1 and when we clone it, then the reference count increases by 1.

Output:

This image has an empty alt attribute; its file name is screenshot-17-1.png

RefCell<T> :

In Rust, Interior mutability pattern is a concept which can help us to mutate the reference, if we have an immutable reference. Then by the use of RefCell<T> we can achieve the interior mutability.

  • It represents the single ownership of the data that it holds.
  • It is only used in the single-threaded program and it will give an error if we use it in a multi-threaded program.
  • If we use RefCell<T>, then the invariants are enforced at the run-time.
  • It checks the mutable borrows at the run-time. We can also mutate the immutable value by the use of RefCell<T>.

For Example:

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

#[derive(Debug)]
enum List
{
    Cons(Rc<RefCell<String>>,Rc<List>),
    Nil,
}

pub fn ref_cell()
{
    let first = Rc::new(RefCell::new(String::from("Python language.")));

    let second = Rc::new(Cons(Rc::clone(&first),Rc::new(Nil)));

    let third = Cons(Rc::new(RefCell::new(String::from("C"))),Rc::clone(&first));

    *third.borrow_mut() = String::from("Rust language");

    println!("value of second variable is : {:?}", second);
    println!("value of third variable is : {:?}", third);
}

In this Example :

We have created a variable ‘first’ and store the value “Python language” in it. Then, created the list ‘second’ and clone the variable ‘first’ so that both variables ‘second’ and ‘first’ have the ownership of ‘Python language’ rather than transferring the ownership from variable ‘first’ to variable ‘second’. After creating list  ‘second’, we have created another list named ‘third’ and clone the list ‘first’ into it . Then we replace the value of the variable ‘first’ with “Rust language” by using the borrow_mut() method in the third list.

Output:

This image has an empty alt attribute; its file name is screenshot-16-3.png

Thanks for Reading the Blog!!!

This image has an empty alt attribute; its file name is blog-footer.jpg

Written by 

Pankaj Chaudhary is a Software Consultant at Knoldus LLP. He has 1.5+ years of experience with good knowledge of Rust, Python, Java, and C. Now he is working as Rust developer and also works on machine learning and data analysis because he loves to play with data and extract some useful information from it. His hobbies are bike riding and explore new places.