I expected MaybeUninit to be a copyless type but according to this snippet (even in release build) it does copy internal value: Rust Playground
What's happening here? Am I missing something?
Old deprecated API std::mem::uninitialized() does not copy data.
As far as I understand, the better way to do this - avoid to use both API, and use array with zero values ( Rust Playground ) , because copying is potentially less effecient (allocating new space may eat many CPU) than filling with zeros.
This kind of copy may appear when a let x = y move happens: the compiler does not yet manage to always elide the copy.
Had you done
let mut p = mem::uninitialised::<[u8; ARRAY_LEN]>();
let x = p;
you would most probably have gotten such memcpy too.
Obviously the dangerous and deprecated mem::uninitialised does not lead to writing that extra move as MaybeUninit::assume_init() does.
That's what MaybeUninit::get_ref() and MaybeUninit::get_mut() are for: they also assume init, only this time they return a reference to the (assumed initialised) data:
#![feature(maybe_uninit_ref)]
use std::mem::MaybeUninit;
const ARRAY_LEN: usize = 1024 * 1204;
type Array = [u8; ARRAY_LEN];
fn main ()
{
let mut raw_array = MaybeUninit::<Array>::uninit();
let at_array: &mut Array = unsafe {
//for example - pass pointer to FFI for init data
::libc::memset(
raw_array.as_mut_ptr() as *mut _,
42,
ARRAY_LEN,
);
raw_array.get_mut()
/* or, without the unstable feature:
/// Use a function to prevent having an unbounded lifetime
unsafe
fn get_mut<T> (raw_array: &'_ mut MaybeUninit<T>) -> &'_ mut T
{
&mut *raw_array.as_mut_ptr()
}
get_mut(&mut raw_array)
*/
};
println!("{:p} -> {:?}", at_array, &at_array[.. 10]);
}
Note that .get_ref() and .get_mut(), on the other hand, do not run the destructor, which means that memory can be leaked when then innards have Drop glue (which should not be the case when doing FFI):
let mut raw_vector = mem::MaybeUninit::<Vec<u8>>::uninit();
let at_vector = unsafe {
raw_vector.as_mut_ptr().write(vec![42]);
raw_vector.get_mut()
};
assert_eq!(&at_vector[..], &[42][..]);
mem::drop(raw_vector); // Memory leak