I need to initialize a vector for use as a buffer. I don’t care what values it contains before I put something in it, so I don’t want the program to waste time filling it with zeroes. I know about with_capacity, but it requires me to push() elements, which is inconvenient because I would need to constantly check if I have pushed something to an index before or not.
Basically, I’m looking for an equivalent of this C++ array:
int* arr = new int[size];
arr[2]; // random garbage
>Solution :
If you cannot fill the vector for performance reasons (but please benchmark!), you need to use unsafe code. You can e.g. use Vec::spare_capacity_mut() (or the nightly Vec::split_at_spare_mut()) to access the elements, then Vec::set_len(). For example:
let mut v = Vec::with_capacity(N);
for (i, item) in v.spare_capacity_mut().iter_mut().enumerate() {
item.write(i);
}
// SAFETY: All elements were initialized.
unsafe {
v.set_len(N);
}
Or you can manually manage the pointers with as_mut_ptr() (less recommended, but may be better if some of the elements are already initialized:
let mut v = Vec::with_capacity(N);
// SFAETY: There are enough elements (even if uninitialized).
let all_elements = unsafe { std::slice::from_raw_parts_mut(v.as_mut_ptr(), N) };
for (i, item) in all_elements.iter_mut().enumerate() {
// SFATETY: Ditto.
unsafe {
std::ptr::write(item, i);
}
}
// SAFETY: All elements were initialized.
unsafe {
v.set_len(N);
}