Skip to content

Vec::with_capacity

Vec methods · Collections

Level: reference · for working programmers

One line: An empty vector with room for n elements already allocated.

pub fn with_capacity(capacity: usize) -> Vec<T>

Stable since 1.0.0. Its const form is still unstable.

The vector is still emptylen() is 0 and indexing it panics. All that exists is the buffer. This is the usual misreading of the name: Vec::with_capacity(10) is not ten zeroes, it is room for ten of something. For ten zeroes, write vec![0; 10].

Use it when you know roughly how many elements are coming. Nine pushes into a Vec::new() reallocate three times, copying everything stored so far on each one; nine pushes into Vec::with_capacity(9) allocate once and copy nothing.

"At least" is the contract. You may get more than you asked for, never less. And capacity is not a limit: the eleventh push into a with_capacity(10) reallocates like any other push — it does not fail.

Reaching for it without a number in hand is not an optimisation. Guessing high wastes memory that shrink_to_fit then has to hand back; guessing low buys nothing. When the count comes from an iterator, collect already does this whenever the iterator knows its own length.

A capacity that would exceed isize::MAX bytes panics rather than returning; try_reserve is the fallible route.

Example

vec_with_capacity.rs in full — pasted here by tools/run_examples.py from the file CI compiles and runs.

fn main() {
    // Capacity is a promise about the buffer, not about the contents.
    let v: Vec<i32> = Vec::with_capacity(10);
    println!("len {} cap {} empty {}", v.len(), v.capacity(), v.is_empty());

    // Ten pushes, one allocation. Watch the pointer stay put.
    let mut sized: Vec<u32> = Vec::with_capacity(9);
    let first = sized.as_ptr() as usize;
    for n in 1..=9 { sized.push(n); }
    println!("moved during 9 pushes: {}", sized.as_ptr() as usize != first);
    println!("cap after 9 pushes: {}", sized.capacity());

    // Without it, the same nine pushes reallocate three times.
    let mut grown: Vec<u32> = Vec::new();
    let mut caps = vec![];
    for n in 1..=9 {
        grown.push(n);
        if caps.last() != Some(&grown.capacity()) { caps.push(grown.capacity()); }
    }
    println!("capacity sequence without with_capacity: {caps:?}");

    // "At least": std may give you more than you asked for, never less.
    let at_least: Vec<u8> = Vec::with_capacity(5);
    println!("asked 5, got at least 5: {}", at_least.capacity() >= 5);

    // The 11th push reallocates anyway — capacity is not a limit.
    let mut ten: Vec<u8> = Vec::with_capacity(10);
    for n in 0..11 { ten.push(n); }
    println!("pushed 11 into cap 10: len {} cap {}", ten.len(), ten.capacity());
}

Verified output of vec_with_capacity.rs — regenerated by tools/run_examples.py, never hand-typed.

len 0 cap 10 empty true
moved during 9 pushes: false
cap after 9 pushes: 9
capacity sequence without with_capacity: [4, 8, 16]
asked 5, got at least 5: true
pushed 11 into cap 10: len 11 cap 20

See also

Vec::with_capacity in the standard library ↗