Rust Lang

Rust Smart Pointers

Pointers are not a new thing to any programmer. They are a feature that allows you to use variables to store an address in memory. The address then “points to”, hence pointer, to data stored in that location.

Smart pointers are pointers with extended capabilities, such as bound checks and automatic memory management. Smart pointers also include additional metadata. Now, the concept of smart pointers is not new, especially to C++ programmers.

For this article, we will explore various smart pointers as defined in the Rust standard library.

Key Points

In Rust, smart pointers are data structures however, unlike normal pointers, smart pointers can actually own data. They are commonly implemented using structs but differ from normal structs in the sense that they implement Deref and Drop traits.

There are 5 smart pointers to know in Rust:

  1. Box<T>
  2. Deref <T>
  3. Drop <T>
  4. Rc<T>
  5. RefCell<T>

NOTE: In Rust <T> refers to the data type.

Keep in mind that will not cover all smart pointers in this article.

Box <T>

The Box<T> smart pointer provides a way to reference data stored in the heap memory. By default, Rust allocates everything on the stack memory. Using the box smart pointer, we can access data on the heap, incurring no performance overhead.

The box smart pointer also obeys the rules of ownership and borrowing. Hence, it has a single owner of data and can have only one mutable reference and any number of immutable references.

fn main() {

// Box<T>

let var = Box::new(100);

println!("Value: {}", var)

}

In the example above, we have a box smart pointer that stores the value 5 in the heap. Keep in mind that the box itself is stored in the stack.

Once the program is terminated, the box is deallocated from the memory.

Deref <T>

As the name suggests, the Deref <T> smart pointer is used to allow manipulation of the dereferencing operation. Using the deref smart pointer, you can create a struct that can work with both smart pointer and references.

An example code is as shown below:

use std::ops::Deref;

struct CustBox<T> {

data: T,

}

impl<T> Deref for CustBox<T> {

// generic type param

type Target = T;

fn deref(&self) ->&T{

&self.data

}

}

fn main() {

let x = CustBox{data: 100};

println!("Value: {}",*(x.deref()))

}

Drop <T>

The Drop smart pointer is used to free memory that is allocated in the heap. The Drop trait in Rust handles free the memory when a variable goes out of scope. We do not need to call this trait manually, as Rust will do this for us. However, we can implement it for custom types as shown.

struct MyStruct {

x: i32,

}

impl Drop for MyStruct {

fn drop(&mut self) {

println!("Dropping: {}", self.x)

}

}

fn main() {

let _x = MyStruct{x: 100};

let _y = MyStruct{x: 200};

}

The above implements the Drop trait for custom trait. The output is as shown:

Dropping: 200

Dropping: 100

Conclusion

In this article, we cover how to create and work with common smart pointers in the Rust programming language. You can learn more about Rust smart pointers in the resource below:

https://doc.rust-lang.org/book/ch15-00-smart-pointers.html

About the author

John Otieno

My name is John and am a fellow geek like you. I am passionate about all things computers from Hardware, Operating systems to Programming. My dream is to share my knowledge with the world and help out fellow geeks. Follow my content by subscribing to LinuxHint mailing list