Skip to content

Week 7 - Smart Pointers and Interior Mutability

7.1 Conceptual Core

  • A "smart pointer" in Rust is a value that owns a heap allocation and customizes Drop. The std hierarchy:
  • Box<T>-unique ownership, single heap allocation.
  • Rc<T>-shared ownership, single-threaded, refcount.
  • Arc<T>-shared ownership, atomic refcount, thread-safe.
  • Weak<T> (paired with Rc/Arc)-non-owning observer; breaks cycles.
  • Interior mutability is the controlled violation of "no &mut while & exists." The valid mechanisms:
  • Cell<T>-get/set by value, no references handed out, single-threaded, zero overhead.
  • RefCell<T>-runtime borrow checking, panics on conflict, single-threaded.
  • Mutex<T> / RwLock<T>-runtime borrow checking with thread blocking, multi-threaded.
  • OnceCell<T> / OnceLock<T>-write-once, then immutable.
  • UnsafeCell<T>-the only primitive that legally permits interior mutability; everything above is built atop it.

7.2 Mechanical Detail

  • UnsafeCell<T> is the one type in the language for which &UnsafeCell<T> may be cast to *mut T without UB, provided the contents are not aliased mutably. Read the Rustonomicon chapter; it is the keystone.
  • The memory layout of Rc<T>: a RcBox<T> { strong: Cell<usize>, weak: Cell<usize>, value: T } allocated as one block. The Rc<T> is a NonNull<RcBox<T>>. Same for Arc<T> but with AtomicUsize and a separate cache line for the refcount on some impls (study triomphe for the alternative layout).
  • Reference cycles: Rc<RefCell<Node>> with two-way edges leaks. The Drop sequencing matters-when refcount reaches zero, the inner value is dropped before the allocation is freed, so cycles in Weak work.
  • Pin preview: introduced here only to flag that interior mutability + self-references is the combination that demands Pin. The full treatment is week 11.

7.3 Lab-"Build a Tracing Rc"

Implement TracingRc<T> from scratch using UnsafeCell and NonNull. It must: - Refcount strong and weak references correctly (study std::rc for the algorithm). - Log every clone/drop to a thread-local trace buffer. - Pass Miri (cargo +nightly miri test)-meaning your unsafe code is provably free of undefined behavior under the stacked-borrows model.

7.4 Idiomatic & Clippy Drill

  • clippy::rc_buffer, clippy::redundant_allocation, clippy::arc_with_non_send_sync, clippy::mut_from_ref. The last is a soundness lint-understand why it can never be silenced legitimately.

7.5 Production Hardening Slice

  • Run your TracingRc lab under cargo +nightly miri test. If it fails, fix the unsoundness; do not silence the diagnostic. Add miri to a nightly CI job as continue-on-error: false.

Comments