enum MaybeNeedsDrop {
Single(f32),
Collection(Vec<f32>)
}
// variant one:
let mut v = Vec::new();
for _ in 0..1000000 {
v.push(MaybeNeedsDrop::Single(1.0));
}
drop(v); /// aaaargh, drop_in_place killing performance, can I not call individual destructors?
// variant two:
let mut v = Vec::new();
for _ in 0..1000000 {
v.push(MaybeNeedsDrop::Collection(vec![1.0, 2.0]));
}
drop(v); // but in this case I want to drop all the nested vectors
How do I conditionally, at runtime, prevent calling destructors of elements
when I know that all items in the vector are of variant that doesn't need calling destructors?
fn drop_vec_forget_elements<T>(vec: Vec<T>) {
let orig = ManuallyDrop::new(vec);
let ptr = orig.as_mut_ptr();
let len = orig.len();
let cap = orig.capacity();
// SAFETY: ManuallyDrop<T> and T have the same layout,
// and we're only dropping the allocation once
let reconstructed: Vec<ManuallyDrop<T>> = unsafe {
Vec::from_raw_parts(ptr, len, cap)
};
drop(reconstructed);
}
Transmuting the Vec directly isn't guaranteed to work, because even if T and U have the same layout, Vec<T> and Vec<U> are not guaranteed to have the same layout. (e.g., they might have the capacity and length stored in different orders.)
fn drop_vec_forget_elements<T>(mut vec: Vec<T>) {
// SAFETY:
// - 0 is always <= capacity
// - every element in range is initialized (there are none)
unsafe {
vec.set_len(0);
}
}