Nurbol Alpysbayev
Nurbol Alpysbayev

Reputation: 21881

When should I use smart pointers?

There is a similar, very popular question for C++, but I couldn't find a similar existing question for Rust.

So, what are the use cases for Box, Rc, Ref, RefMut (others?) in Rust?

The important part of the question (for me personally): when should smart pointers be used instead of references?

I know The Rust Book explains it very, very thoroughly, but I wish there would be a succinct and quick "cheatsheet" on the subject, possibly with some real-world examples that are missing in the book.

Upvotes: 2

Views: 967

Answers (2)

Optimistic Peach
Optimistic Peach

Reputation: 4288

What are the use cases for Box, Rc, Ref, RefMut (others?) in Rust?

Okay, here we go:

  • Box, in the simplest terms, is used when you have an object you want to keep on the heap. Use a box when
  • Rc is used when it is very difficult to decide on the lifetimes of objects. It's a sign of laziness to overuse, and somewhat defeats the purpose of lifetimes.
  • Ref and RefMut are the objects produced by a RefCell when you try to get access to its contents. A RefCell will track the borrowing state of its object at runtime instead of compile time, so it is kind of like lifetimes. A general use for this is when you need to have mutable references to many objects in a hashmap for example.
  • Arc is used with either RwLock (Essentially the same as RefCell apart from what's below) or Mutex when trying to share an object across a thread boundary. The examples on their pages will show you how to use them and why they are important as opposed to using the Rc<RefCell<T>> pattern.

There are a few more "smart" pointers per se in rust, but what you must know is that everything will eventually de-allocate its contents unless you've used unsafe code or used the global allocator directly.

This ties into why the tools built into the language (lifetimes) are so important to Rust, they accomplish all that Rc and RefCell accomplish but without the performance drawbacks and also do what C/C++ do without the chance of UB.

Upvotes: 6

David Brown
David Brown

Reputation: 247

The simple answer I would give would be: use references when you can. Unfortunately, understanding when you can depends on getting a deeper understanding of the borrow checker, and by that point, I would guess a cheat sheet would be less useful. However, some simple explanations might help.

  • The simple case is where you have a clear owner, and references are passed down the stack to functions that you call. This case works clearly for just references.
  • When you have the same clear ownership but the item is either "large", or of non-determined size, you may need a Box. Still a single owner, with possible stack-based borrowing.
  • When ownership isn't clearly in a tree, Rc or Arc would be appropriate (with something like a Mutex for sharing).

The other things mentioned (Ref, RefMut) are specifically about borrows of the thing contained in a RefCell. Cell and RefCell are containers that are mutable.

I would say, start by trying to just have your item owned, and using borrowed references to pass it around. If you do need sharing, look into Rc or Arc. If that still doesn't work, consider the other things.

Again, though, the Rust Book's description is very good, and you kind of have to get an understanding of borrowing to get a gut feeling of what to use anyway.

Upvotes: 2

Related Questions