Smart Pointers in Rust: What, why and how?
Tags: beginners, rust, programming, learning
Published: 2021-07-19 15:25:22

> **TL;DR:** I will cover some of Rust's smart pointers: `Box`, `Cell`, `RefCell`, `Rc`, `Arc`, `RwLock` and `Mutex`.

It seems pretty obvious that smart pointers are pointers that are... _smart_. But **what** exactly does this "smart" means? **When** should we use them? **How** do they work? 

These are the questions I will begin to answer here. And that is it: _the beginning of an answer_, nothing more. I expect that this article will give you a "background of understanding" (something like "familiarity" with the concept) that will help you accommodate a real understanding of the topic, which will come from reading the official documentation and, of course, practice.

> _If you are already familiar with it, you may use this text as a list of relevant reading. Look for the "useful links" at the beginning of each section._

**Index:**
1. [Box](#box)
2. [Cell](#cell)
3. [RefCell](#refcell)
4. [Rc](#rc)
5. [Arc](#arc)
6. [RwLock](#rwlock)
7. [Mutex](#mutex)

---

## Smart points in general
As explained in [_The Book_](https://doc.rust-lang.org/book/ch15-00-smart-pointers.html), pointers are variables containing an address that "points at" some other data. The usual pointer in Rust is the reference (`&`). Smart pointers are pointers that "have additional metadata and capabilities", e.g., they may count how many times the value was borrowed, provide methods to manage read and write locks, etc.

Technically speaking, `String` and `Vec` are also smart pointers, but I will not cover them here as they are quite common and are usually thought of as types rather than pointers.

Also note that, from this list, only `Arc`, `RwLock`, and `Mutex` are thread-safe.

---

## <a name="box"></a>Box\<T>
Useful links: [The Book](https://doc.rust-lang.org/book/ch15-01-box.html); [Documentation](https://doc.rust-lang.org/std/boxed/struct.Box.html); [Box, stack and heap](https://doc.rust-lang.org/rust-by-example/std/box.html).

### What?
`Box<T>` allows you to store `T` on the heap. So, if you have, say, a `u64` that would be stored on the stack, `Box<u64>` will store it on the heap.

> If you are not comfortable with the concepts of stack and heap, read [this](https://doc.rust-lang.org/book/ch04-01-what-is-ownership.html?highlight=stack#the-stack-and-the-heap).

### Why?
Values stored on the stack cannot grow, as Rust needs to know its size at compile time. The best example of how this may affect your programming that I know is in [_The Book_](https://doc.rust-lang.org/book/ch15-01-box.html?highlight=recursion#enabling-recursive-types-with-boxes): **recursion**. Consider the code below (and its comments).

```rust
// This does not compile. The List contains itself,  
// being recursive and therefore having an infinite size.
enum List { 
   Cons(i32, List),
   Nil,
}
// This does compile because the size of a pointer
// does not change according to the size of the pointed value.
enum List { 
   Cons(i32, Box<List>),
   Nil,
}
```

Be sure to read [this section on _The Book's_](https://doc.rust-lang.org/book/ch15-01-box.html?highlight=recursion#enabling-recursive-types-with-boxes) to understand the details.

On a more general note, `Box` is useful when your value is too big to be kept on the stack or when you need to [own](https://doc.rust-lang.org/book/ch04-00-understanding-ownership.html) it.

### How?
To get the value `T` inside `Box<T>` you just have to deref it.
```rust
let boxed = Box::new(11);
assert_eq!(*boxed, 11)
```

---

## <a name="cell"></a>Cell\<T>
Useful links: [Module documentation](https://doc.rust-lang.org/std/cell/); [Pointer documentation](https://doc.rust-lang.org/std/boxed/struct.Box.html).

### What?
`Cell<T>` gives a shared reference to `T` while allowing you to change `T`.  This is one of the  "shareable mutable containers" provided by the module [`std::cell`](https://doc.rust-lang.org/std/cell/).

### Why?
In Rust, shared references are immutable. This guarantees that when you access the inner value you are not getting something different than expected, as well as assure that you are not trying to access the value after it was freed (which is a big chunk of those [70% of security bugs that are memory safety issues](https://www.zdnet.com/article/chrome-70-of-all-security-bugs-are-memory-safety-issues/)).

### How?
What `Cell<T>` does is provide functions that control our access to `T`. You can find them all [here](https://doc.rust-lang.org/std/cell/struct.Cell.html), but for our explanation we just need two: `get()` and `set()`. 

Basically, `Cell<T>` allows you to freely change `T` with `T.set()` because when you use `T.get()`, you retrieve [`Copy`](https://doc.rust-lang.org/std/marker/trait.Copy.html) of `T`, not a reference. That way, even if you change `T`, the copied value you got with `get()` will remain the same, and if you destroy `T`, no pointer will dangle.

One last note is that `T` has to implement `Copy` as well.

```rust
use std::cell::Cell;
let container = Cell::new(11);
let eleven = container.get();
{
    container.set(12);
}
let twelve = container.get();
assert_eq!(eleven, 11);
assert_eq!(twelve, 12);
```

---

## <a name="refcell"></a>RefCell\<T>
Useful links: [The Book](https://doc.rust-lang.org/book/ch15-05-interior-mutability.html); [Documentation](https://doc.rust-lang.org/std/cell/struct.RefCell.html).

### What?
`RefCell<T>` also gives shared reference to `T`, but while `Cell` is statically checked (Rust checks it at compile time), `RefCell<T>` is dynamically checked (Rust checks it at run time).

### Why?
Because `Cell` operates with copies, you should restrict yourself to using small values with it, which means that you need references once again, which leads us back to the problem that `Cell` solved. 

The way `RefCell` deals with it is by keeping track of who is reading and who writing  `T`. That's why `RefCell<T>` is dynamically checked: because **you** are going to code this check. But fear not, Rust will still make sure you don't mess up at compile time.

### How?
`RefCell<T>` has methods that borrow either a mutable or immutable reference to  `T`; methods that will not allow you to do so if this action would be unsafe. As with `Cell`, there are several methods in `RefCell`, but these two are enough to illustrate the concept: `borrow()`, which gets an immutable reference; and `borrow_mut()`, which gets a mutable reference. The logic used by `RefCell` goes something like this:
- If there is **no reference** (either mutable or immutable) to `T`, you may get either a mutable or immutable reference to it;
- If there is already a **mutable reference** to `T`, you may get nothing and got to wait until this reference is dropped;
- If there are one or more **immutable references** to `T`, you may get an immutable reference to it.

As you can see, there is no way to get both mutable and immutable references to `T` at the same time.

> _**Remember:** this is **not** thread-safe. When I say "no way", I am talking about a single thread._

Another way to think about is:
- **Immutable** references are **shared** references;
- **Mutable** references are **exclusive** references.

It is worth to say that the functions mentioned above have variants that do not panic, but returns `Result` instead: `try_borrow()` and `try_borrow_mut()`;

```rust
use std::cell::RefCell;
let container = RefCell::new(11);
{
    let _c = container.borrow();
    // You may borrow as immutable as many times as you want,...
    assert!(container.try_borrow().is_ok());
    // ...but cannot borrow as mutable because 
    // it is already borrowed as immutable.
    assert!(container.try_borrow_mut().is_err());
} 
// After the first borrow as mutable...
let _c = container.borrow_mut();
// ...you cannot borrow in any way.
assert!(container.try_borrow().is_err());
assert!(container.try_borrow_mut().is_err());
```

---

## <a name="rc"></a>Rc\<T>
Useful links: [The Book](https://doc.rust-lang.org/book/ch15-04-rc.html); [Module documentation](https://doc.rust-lang.org/std/rc/index.html); [Pointer documentation](https://doc.rust-lang.org/std/rc/struct.Rc.html); [Rust by example](https://doc.rust-lang.org/rust-by-example/std/rc.html).

### What?
I will quote the documentation on this one:

> The type `Rc<T>` provides shared ownership of a value of type `T`, allocated on the heap. Invoking [`clone`](https://doc.rust-lang.org/std/clone/trait.Clone.html#tymethod.clone) on `Rc` produces a new pointer to the same allocation on the heap. When the last `Rc` pointer to a given allocation is destroyed, the value stored in that allocation (often referred to as “inner value”) is also dropped.

So, like a `Box<T>`, `Rc<T>` allocates `T` on the heap. The difference is that cloning `Box<T>` will give you another `T` inside another `Box` while cloning `Rc<T>` gives you another `Rc` to the **same** `T`.

Another important remark is that we don't have interior mutability in `Rc` as we had in `Cell` or `RefCell`. 

### Why?
You want to have shared access to some value (without making copies of it), but you want to let it go once it is no longer used, i.e., when there is no reference to it.

As there is no interior mutability in `Rc`, it is common to use it alongside `Cell` or `RefCell`, for example, `Rc<Cell<T>>`.

### How?
With `Rc<T>`, you are using the `clone()` method. Behind the scene, it will count the number of references you have and, when it goes to zero, it drops `T`.

```rust
use std::rc::Rc;
let mut c = Rc::new(11);

{ 
    // After borrwing as immutable...
    let _first = c.clone();

    // ...you can no longer borrow as mutable,...
    assert_eq!(Rc::get_mut(&mut c), None);

    // ...but can still borrow as immutable.
    let _second = c.clone();

    // Here we have 3 pointer ("c", "_first" and "_second").
    assert_eq!(Rc::strong_count(&c), 3);
}

// After we drop the last two, we remain only with "c" itself.
assert_eq!(Rc::strong_count(&c), 1);

// And now we can borrow it as mutable.
let z = Rc::get_mut(&mut c).unwrap();
*z += 1;
assert_eq!(*c, 12);
```
---

## <a name="arc"></a>Arc\<T>
Useful links: [Documentation](https://doc.rust-lang.org/std/sync/struct.Arc.html); [Rust by example](https://doc.rust-lang.org/rust-by-example/std/arc.html).

### What?
`Arc` is the thread-safe version of `Rc`, as its counter is managed through atomic operations.

### Why?
I think the reason why you would use `Arc` instead of `Rc` is clear (thread-safety), so the pertinent question becomes: why not just use `Arc` _every_ time? The answer is that these extra controls provided by `Arc` come with an overhead cost. 

### How?
Just like `Rc`,  with `Arc<T>` you will be using `clone()` to get a pointer to the same value `T`, which will be destroyed once the last pointer is dropped.

```rust
use std::sync::Arc;
use std::thread;

let val = Arc::new(0);
for i in 0..10 {
    let val = Arc::clone(&val);

    // You could not do this with "Rc"
    thread::spawn(move || {
        println!(
            "Value: {:?} / Active pointers: {}", 
            *val+i, 
            Arc::strong_count(&val)
        );
    });
}
```

---

## <a name="rwlock"></a>RwLock\<T>
Useful link: [Documentation](https://doc.rust-lang.org/std/sync/struct.RwLock.html).

> `RwLock` is also provided by the [`parking_lot`](https://docs.rs/parking_lot/0.10.2/parking_lot/type.RwLock.html) crate.

### What?
As a reader-writer lock, `RwLock<T>` will only give access to `T` once you are holding one of the locks: `read` or `write`, which are given following these rules:
- **To read**: If you want a lock to read, you may get it as long as _no writer_ is holding the lock; otherwise, you have to wait until it is dropped;
- **To write**: If you want a lock to write, you may get as long as _no one_, reader or writer, is holding the lock; otherwise, you have to wait until they are dropped;

### Why?
`RwLock` allows you to read and write the same data from multiple threads. Different from `Mutex` (see below), it distinguishes the kind of lock, so you may have several `read` locks as far as you do not have any `write` lock.

### How?
When you want to read a `RwLock`, you got to use the function `read()`—or `try_read()`—that will return a `LockResult` that contains a `RwLockReadGuard`. If it is successful, you will be able to access the value inside `RwLockReadGuard` by using deref. If a writer is holding the lock, the thread will be blocked until it can take hold of the lock. 

Something similar happens when you try to use `write()`—or `try_write()`. The difference is that it will not only wait for a writer holding the lock, but for any reader holding the lock as well.

```rust
use std::sync::RwLock;
let lock = RwLock::new(11);

{
    let _r1 = lock.read().unwrap();
    // You may pile as many read locks as you want.
    assert!(lock.try_read().is_ok());
    // But you cannot write.
    assert!(lock.try_write().is_err());
    // Note that if you use "write()" instead of "try_write()"
    // it will wait until all the other locks are released
    // (in this case, never).
} 

// If you grab the write lock, you may easily change it
let mut l = lock.write().unwrap();
*l += 1;
assert_eq!(*l, 12);
```

If some thread holding the lock panics, further attempts to get the lock will return a [`PoisonError`](https://doc.rust-lang.org/std/sync/struct.PoisonError.html), which means that from then on every attempt to read `RwLock` will return the same `PoisonError`. You may recover from a poisoned `RwLock` using `into_inner()`. 

```rust
use std::sync::{Arc, RwLock};
use std::thread;

let lock = Arc::new(RwLock::new(11));
let c_lock = Arc::clone(&lock);

let _ = thread::spawn(move || {
    let _lock = c_lock.write().unwrap();
    panic!(); // the lock gets poisoned
}).join();

let read = match lock.read(){
    Ok(l) => *l,
    Err(poisoned) => {
        let r = poisoned.into_inner();
        *r + 1
    }
};

// It will be 12 because it was recovered from the poisoned lock
assert_eq!(read,12);
```

---

## <a name="mutex"></a>Mutex\<T>
Useful links: [The Book](https://doc.rust-lang.org/book/ch16-03-shared-state.html); [Documentation](https://doc.rust-lang.org/std/sync/struct.Mutex.html).

> `Mutex` is also provided by the [`parking_lot`](https://docs.rs/parking_lot/0.10.0/parking_lot/type.Mutex.html) crate.

### What?
`Mutex` is similar to `RwLock`, but it only allows one lock-holder, no matter if it is a reader or a writer. 

### Why?
One reason to prefer `Mutex` over `RwLock` is that `RwLock`  may lead to writer starvation (when the readers pile on and the writer never gets a chance to take the lock, waiting forever), something the does not happen with `Mutex`.  

Of course, we are diving into deeper seas here, so the real-life choice falls on more advanced considerations, such as how many readers you expect at the same time, how the operating system implements the locks, and so on...

### How?
`Mutex` and `RwLock` work in a similar fashion, the difference is that, because `Mutex` does not differentiate between readers and writers, you just use `lock()` or `try_lock` to get the `MutexGuard`. The poisoning logic also happens here.

```rust
use std::sync::Mutex;
let guard = Mutex::new(11);

let mut lock = guard.lock().unwrap();
// It does not matter if you are locking the Mutex to read or write,
// you can only lock it once.
assert!(guard.try_lock().is_err());

// You may change it just like you did with RwLock
*lock += 1;
assert_eq!(*lock, 12);
```

You can deal with poisoned `Mutex` in the same way as you deal with poisoned `RwLock`.

---

Thank you for reading!