liveBook · Manning

Smart pointer

As explained in Idiomatic Rust

A smart pointer is a pointer-like value that manages or mediates access to the data it references.

A smart pointer is a pointer-like value that manages access to what it points to. In C++, RAII uses constructors and destructors so a smart pointer such as `std::shared_ptr` releases allocated memory when it goes out of scope, including on an early return or exception. Rust offers different smart pointers for different ownership and storage needs. section 4.1.1 section 10.8

Choose by the ownership you need:

  • Use `Box` for heap allocation without shared ownership. It can also hold a value whose size is not known at compile time inside a fixed-size object. section 10.8
  • Use `Rc` when multiple owners share a value without sharing ownership across threads. section 10.8
  • Use `Arc` when ownership must be shared across threads. Its atomic reference counting does not synchronize the value itself. section 10.8
  • Use `Cell` or `RefCell` for interior mutability; they are often paired with shared-ownership pointers rather than providing shared ownership themselves. section 10.8

Smart pointers also make trait objects practical. A trait object is unsized, so it cannot be stored directly as a `Vec` element. A `Box` can hold it: construct a concrete value, then use it as `Box<dyn MyTrait>`. Through that trait object, only the trait’s methods are available without a downcast. section 2.2.6

let mut v = Vec::<Box<dyn MyTrait>>::new();

v.push(Box::new(MyStruct1 {}));          #1
v.push(Box::new(MyStruct2 {}));            #2

v.iter().for_each(|i| i.trait_hello());                   #3
// v.iter().for_each(|i| i.struct_hello()); error!    #4

A `Vec<Box<dyn MyTrait>>` holds two concrete types; calling a concrete-only method through the trait object is marked as an error. section 2.2.6

Listing 10.14 Overusing smart pointers
let mut string_box_vec: Vec<Box<String>> =
    vec![Box::new(                                  #1
        String::from("unecessarily boxed string")   #1
    )];                                             #1
let mut string_vec: Vec<String> =
    vec![String::from("this is okay")];       #2

let boxed_string = string_box_vec.remove(0);     #3
let normal_string = string_vec.remove(0);      #4

Compare `Vec<Box<String>>` with `Vec<String>`. Boxing an already heap-allocated string inside a vector can add an unnecessary allocation. section 10.8

Do not add `Rc` merely because cloning a pointer is easier than working through ownership and borrowing. Smart pointers are useful, but the wrong one—or too many—can obscure a design. If one is serving mainly as an escape hatch from the borrow checker, reconsider the design. section 10.8 section 10.10

How Idiomatic Rust covers it

How deep it goes
Explains pointer selection and allocation tradeoffs with Rust examples, but does not detail reference-counting internals.
Examples
Compares `Vec<Box<String>>` with `Vec<String>` and stores two concrete types in a `Vec<Box<dyn MyTrait>>`.
What it assumes
Assumes familiarity with Rust ownership, borrowing, vectors, and traits rather than teaching them from zero.
What you can do after
Evaluate/understand when to use `Box`, `Rc`, or `Arc` and when extra smart pointers signal needless allocation or avoided borrowing.
How it connects
Connects smart pointers to RAII, ownership, borrowing, interior mutability, trait objects, and the borrow checker.

Also explained in

Compare how 5 books explain smart pointer →

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Idiomatic Rust. The section links point to the parts of the book it draws on.