MaybeUninit.write() vs assignment

use std::mem::MaybeUninit;

fn main() {
    let mut buf = MaybeUninit::<String>::uninit();

    // Initialize
    buf.write(String::from("Hello, Rust!"));

    // Overwrite
    buf.write(String::from("Hi again"));

    // Assignment replaces the whole MaybeUninit value.
    buf = MaybeUninit::new(String::from("Goodbye"));

    // Ensure inner value is dropped
    let _ = unsafe { buf.assume_init() };
}

Replacing inner values can cause memory leaks because the drop semantics differ from most types. MaybeUninit<T> does not call the destructor on its T.

MaybeUninit::write() uses ptr::write: it initializes the memory in place without reading or dropping the old contents. That is exactly what you want when the memory might be uninitialized, but it also means you will leak if there was already a live value there.

Assignment, e.g. buf = MaybeUninit::new(value), replaces the whole MaybeUninit. The old MaybeUninit is moved and then dropped, but MaybeUninit has no destructor for T, so the inner value is not dropped. If the old slot held an initialized value, it is leaked just like with write().

If you need normal drop behavior, you need to tell Rust that the value is initialized with assume_init or one of the related methods.