Vec::into_raw_parts¶
Level: reference · for working programmers
One line: Decompose the vector into (pointer, length, capacity) and stop managing it.
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::from_raw_parts— the way backVec::leak— the same handover, without the numbersVec::as_ptr— the pointer, without giving up ownershipVec::into_boxed_slice— the safe way to hand off a buffer