In this lesson, you will learn why some Rust collections allow you to keep valid references even when you add more items, while others force those references to become invalid.
The Problem: When Memory Moves
Imagine you have a Vec<i32>. A vector is a contiguous block of memory. When it runs out of space, it allocates a brand-new, larger block of memory elsewhere and copies all existing elements over. If you had a reference to an element in the old block, that reference now points to "stale" memory that has been deallocated. This is why the Rust compiler forbids you from holding a reference to a vector element while simultaneously pushing new items into that same vector—it’s protecting you from a "use-after-free" bug.
The Solution: Stable Pointers
If you need references that stay valid even as your collection grows, you must choose a data structure that does not move its elements.
A great example is a LinkedList or a VecDeque (in certain scenarios), but specifically, data structures that use indirection. When you use something like Vec<Box<T>> or a LinkedList<T>, the elements are stored in separate heap allocations. When you add a new item, the collection only updates its internal pointers to link to the new node. The existing nodes stay exactly where they were in memory.
Here is how you might visualize the safety:
use std::collections::LinkedList;
fn main() {
let mut list = LinkedList::new();
list.push_back(10);
list.push_back(20);
// This reference remains valid even if we add more items,
// because the '10' is in its own heap-allocated node.
let reference_to_first = list.front().unwrap();
list.push_back(30);
println!("The first item is still: {}", reference_to_first);
}
Because LinkedList nodes are linked via pointers rather than being packed side-by-side in a single contiguous buffer, adding a new element doesn't require "shuffling" the existing ones. The memory address of the first node never changes.
When designing your architecture, ask yourself: "Will I need to reference individual items while the collection grows?" If the answer is yes, prioritize collections that offer reference stability by design, rather than those that optimize for tight, contiguous memory packing.
Key Takeaway: Reference stability is a trade-off; collections that store elements in separate, stable memory allocations allow you to hold references during mutations, while contiguous structures like Vec may invalidate your references when they reallocate.