Skip to content

Smart Pointer

Updated
17 Sept 2026
3 min read
0 sections
Page 9 of 18
Rust
  • A pointer is a variable that stores the memory address, which points to any other data in the memory.
  • Most common pointer is the reference (only simply borrow the value, they point to, i.e. doesn't have ownership of the value).
  • References doesn't have any special capabilities, i.e. they doesn't have overhead (unlike pointers).
  • Smart Pointers are data structures that act like pointers, but also have additional metadata and capabilities.
  • In many cases, smart pointers have ownership of the data they point to (unlike references, which simply borrow values).
  • Smart pointers are implemented using structs (they implement the deref{:rust} & drop{:rust} traits).
  • deref{:rust} trait allows an instance of the smart pointer struct to behave like a reference, so that you can write code that works with either references or smart pointers.
  • drop{:rust} trait allows you to customize the code that is run when an instance of the smart pointer goes out of scope.

Box Smart Pointer

rust
fn main() {
    let b = Box::new(5);

    println!("b = {}", b);
}
  • Box{:rust} is a smart pointer, it stores address of the heap memory, where the value 5 is stored.
  • Boxes doesn't have overhead, except storing data in the heap (but they have very limited capabilities)

Usage:

Boxes are useful when you have a type whose size can't be known at compile time and you want to use a value of that type in a context that requires an exact size.

Example:

rust
enum List {
    Cons(i32, List),
    Nil,
}

use List::{ Cons, Nil };

fn main() {
    let list = Cons(1, Cons(2, Cons(3, Nil)));
}
recursive type List{:rust} has infinite size
powershell
2 |     Cons(i32, List), |               ---- recursive without indirection
  • Cons(){:rust} constructs memory objects which hold two values or pointers to two values.

Fix:

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

use List::{ Cons, Nil };

fn main() {
    let list = Cons(1, Box::new(Cons(2, Box::new(Cons(3, Box::new(Nil))))));
}
  • Box{:rust} instead of calculating the size of the type at compile time, it stores the address of the heap memory, where the value is stored.

Deref Trait

  • deref{:rust} trait allows an instance of the smart pointer struct to behave like a reference, so that you can write code that works with either references or smart pointers.
rust
fn main() {
    let x = 5;
    let y = &x;

    assert_eq!(5, x);
    assert_eq!(5, y);
}
Error: no implementation for {integer} == &{integer}{:rust}
rust
fn main() {
    let x = 5;
    let y = &x;

    assert_eq!(5, x);
    assert_eq!(5, *y);
}
  • *y{:rust} dereferences the reference y{:rust} to get the value it points to.

Deref Trait with Smart Pointers:

rust
fn main() {
    let x = 5;
    let y = Box::new(x);

    assert_eq!(5, x);
    assert_eq!(5, *y);
}
  • Box{:rust} smart pointer implements the deref{:rust} trait, which allows it to be dereferenced like a reference.
  • Here *y{:rust} dereferences the Box{:rust} smart pointer, to get the value from the address storing the duplicate value stored in heap.

Custom Smart Pointer

  • Implementing the Deref{:rust} trait on your own data structures allows you to use all the methods provided by the standard library.
rust
use std::ops::Deref;

struct MyBox<T>(T);

impl<T> MyBox<T> {
    fn new(x: T) -> MyBox<T> {
        MyBox(x)
    }
}
impl<T> Deref for MyBox<T> {
    type Target = T;

    fn deref(&self) -> &T {
        &self.0
    }
}

fn main() {
    let x = 5;
    let y = MyBox::new(x);

    assert_eq!(5, x);
    assert_eq!(5, *y);
}

Implicit Deref Coercions

  • Implicit Deref Coercion is a convenience that Rust performs on arguments to functions and methods which implement the Deref{:rust} trait.
  • It is used to convert a reference of one type into a reference of another type.
rust
fn main() {
    let m = MyBox::new(String::from("Rust"));

    hello(&m);
    hello(&(*m)[..]);
}

fn hello(name: &str) {
    println!("Hello, {}!", name);
}
  • Implicit Deref Coercion: &MyBox<String>{:rust} -> &String{:rust} -> &str{:rust}
  • &(*m){:rust} dereferences the MyBox<String>{:rust}, then & creates a reference to the String, and [..]{:rust} gets a slice of String{:rust}.
Rust cannot perform deref coercion: \ \ From &T{:rust}(immutable reference) to &mut U{:rust} (mutable reference)

Drop Trait

  • drop{:rust} trait allows you to customize the code that is run when an instance of the smart pointer goes out of scope.
  • It automatically runs when the value goes out of scope.
rust
struct CustomSmartPointer {
    data: String,
}

impl Drop for CustomSmartPointer {
    fn drop(&mut self) {
        println!("Dropping CustomSmartPointer with data `{}`!", self.data);
    }
}

fn main() {
    let c = CustomSmartPointer { data: String::from("my stuff") };
    let d = CustomSmartPointer { data: String::from("other stuff") };
    println!("CustomSmartPointers created.");
    drop(d);
    println!("CustomSmartPointer dropped before the end of main.");
}
Out · output
CustomSmartPointers created.
Dropping CustomSmartPointer with data `other stuff`!
CustomSmartPointer dropped before the end of main.
Dropping CustomSmartPointer with data `my stuff`!