I was trying to initialize an array using a user provided callback function. So I figured I would use mem::unitialized
to do (The Rustonomicon suggests that this is allowed, as it provided example of that function with arrays). This function works... sorta.
use std::mem;
use std::ptr;
fn init_array<T, F: Fn() -> T>(f: F) -> [T; 20] {
unsafe {
let mut arr: [T; 20] = mem::uninitialized();
for item in &mut arr {
ptr::write(item, f());
}
arr
}
}
However, there is a possibility of panic occuring, as a function is provided by a quite panicky programmer. If that were to happen, and T
would have a Drop
implementation, then Drop
would be called on uninitialized value, and it would likely lead to undefined behaviour, which as most C programmers will tell you is worst thing ever.
So an array could be wrapped in a type that has a Drop
implementation whose purpose is to only drop elements that were assigned (while also storing array length). However, currently Rust appear doesn't provide a way to stop implicit drop
calls for each structure element after calling drop
function.
The Rustonomicon suggests to use an Option
type as a workaround to make sure array value is None
after leaving drop
function. However, this doesn't exactly work. With null pointer optimization (caused in a type like Option<[&i32; 20]>
), Option
type tag is not written in output assembly, as Rust trusts the type to have a non-zero value (which normally would be the case).
Can somebody suggest me either how to do it with unsafe code, or better yet, a module that does so or a way to do it in a safe code without doing allocations (so storing values in Vec<T>
, and then moving them is not an option).