Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

converting `MaybeUninit<T>` to `T`, but getting error E0382

I’m trying to reproduce the code suggested in the MaybeUninit docs. Specifically, it seems to work with specific datatypes, but produces a compiler error on generic types.

Working example (with u32)

use std::mem::{self, MaybeUninit};

fn init_array(t: u32) -> [u32; 1000] {
    // Create an uninitialized array of `MaybeUninit`. The `assume_init` is
    // safe because the type we are claiming to have initialized here is a
    // bunch of `MaybeUninit`s, which do not require initialization.
    let mut data: [MaybeUninit<u32>; 1000] = unsafe { MaybeUninit::uninit().assume_init() };

    // Dropping a `MaybeUninit` does nothing. Thus using raw pointer
    // assignment instead of `ptr::write` does not cause the old
    // uninitialized value to be dropped. Also if there is a panic during
    // this loop, we have a memory leak, but there is no memory safety
    // issue.
    for elem in &mut data[..] {
        elem.write(t);
    }

    // Everything is initialized. Transmute the array to the
    // initialized type.
    unsafe { mem::transmute::<_, [u32; 1000]>(data) }
}

fn main() {
    let data = init_array(42);
    assert_eq!(&data[0], &42);
}

Failing example (with generic T)

use std::mem::{self, MaybeUninit};

fn init_array<T: Copy>(t: T) -> [T; 1000] {
    // Create an uninitialized array of `MaybeUninit`. The `assume_init` is
    // safe because the type we are claiming to have initialized here is a
    // bunch of `MaybeUninit`s, which do not require initialization.
    let mut data: [MaybeUninit<T>; 1000] = unsafe { MaybeUninit::uninit().assume_init() };

    // Dropping a `MaybeUninit` does nothing. Thus using raw pointer
    // assignment instead of `ptr::write` does not cause the old
    // uninitialized value to be dropped. Also if there is a panic during
    // this loop, we have a memory leak, but there is no memory safety
    // issue.
    for elem in &mut data[..] {
        elem.write(t);
    }

    // Everything is initialized. Transmute the array to the
    // initialized type.
    unsafe { mem::transmute::<_, [T; 1000]>(data) }
}

fn main() {
    let data = init_array(42);
    assert_eq!(&data[0], &42);
}

error:

   Compiling playground v0.0.1 (/playground)
error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
  --> src/main.rs:20:14
   |
20 |     unsafe { mem::transmute::<_, [T; 1000]>(data) }
   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   |
   = note: source type: `[MaybeUninit<T>; 1000]` (size can vary because of T)
   = note: target type: `[T; 1000]` (size can vary because of T)

For more information about this error, try `rustc --explain E0512`.
error: could not compile `playground` due to previous error

Playground link here

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

Questions

  1. why is the second example failing? (I thought MaybeUninit<T> could always be transmuted into a T because they’d be guaranteed to have the same memory layout.)
  2. can the example be rewritten to work with generic types?

>Solution :

This is a known issue (related), you can fix the code using the tips of HadrienG2 by doing a more unsafe unsafe thing:

// Everything is initialized. Transmute the array to the
// initialized type.
let ptr = &mut data as *mut _ as *mut [T; 1000];
let res = unsafe { ptr.read() };
core::mem::forget(data);
res

In future we expect to be able to use array_assume_init().

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading