Skip to content

Vec::into_raw_parts

Vec methods · Collections

Level: reference · for working programmers

One line: Decompose the vector into (pointer, length, capacity) and stop managing it.

pub fn into_raw_parts(self) -> (*mut T, usize, usize)

Stable since 1.93.0. Its const form is still unstable.

The vector is gone and nothing is freed: from here the allocation is yours to account for. It is leak with the receipt kept.

Capacity is the number people drop, and it is the one the allocator needs back. A vector of length 1 and capacity 16 must be reconstructed with 16, or the deallocation is wrong. Length alone is not enough.

The only safe end for the three numbers is handing them to from_raw_parts with the same T.

Between the two calls the pointer behaves like any raw pointer: reads through it are unsafe, and nothing tracks the elements' lifetimes.

Stable since 1.93.0 — before that the spelling was let mut v = ManuallyDrop::new(v); (v.as_mut_ptr(), v.len(), v.capacity()).

Example

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

fn main() {
    let v = vec![10u32, 20, 30];
    println!("before: {v:?} len {} cap {}", v.len(), v.capacity());

    // Hand over the three numbers. The Vec is gone and nothing was freed:
    // from here on the allocation is yours to account for.
    let (ptr, len, cap) = v.into_raw_parts();
    println!("into_raw_parts: len {len} cap {cap} ptr non-null {}", !ptr.is_null());

    // Read through the pointer without going back through a Vec.
    let first = unsafe { *ptr };
    println!("first element read through the raw pointer: {first}");

    // The only safe end for it is handing the same three numbers back.
    let restored = unsafe { Vec::from_raw_parts(ptr, len, cap) };
    println!("restored: {restored:?} len {} cap {}", restored.len(), restored.capacity());

    // Capacity, not length, is what the allocator needs back — so it has to
    // survive the round trip too.
    let mut v: Vec<u8> = Vec::with_capacity(16);
    v.push(1);
    let (p, l, c) = v.into_raw_parts();
    println!("len {l} but cap {c} — the deallocation needs the second number");
    drop(unsafe { Vec::from_raw_parts(p, l, c) });
}

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

before: [10, 20, 30] len 3 cap 3
into_raw_parts: len 3 cap 3 ptr non-null true
first element read through the raw pointer: 10
restored: [10, 20, 30] len 3 cap 3
len 1 but cap 16 — the deallocation needs the second number

See also

Vec::into_raw_parts in the standard library ↗