The documentation for mem::uninitialized
points out why it is dangerous/unsafe to use that function: calling drop
on uninitialized memory is undefined behavior.
So this code should be, I believe, undefined:
let a: TypeWithDrop = unsafe { mem::uninitialized() };
panic!("=== Testing ==="); // Destructor of `a` will be run (U.B)
However, I wrote this piece of code which works in safe Rust and does not seem to suffer from undefined behavior:
#![feature(conservative_impl_trait)]
trait T {
fn disp(&mut self);
}
struct A;
impl T for A {
fn disp(&mut self) { println!("=== A ==="); }
}
impl Drop for A {
fn drop(&mut self) { println!("Dropping A"); }
}
struct B;
impl T for B {
fn disp(&mut self) { println!("=== B ==="); }
}
impl Drop for B {
fn drop(&mut self) { println!("Dropping B"); }
}
fn foo() -> impl T { return A; }
fn bar() -> impl T { return B; }
fn main() {
let mut a;
let mut b;
let i = 10;
let t: &mut T = if i % 2 == 0 {
a = foo();
&mut a
} else {
b = bar();
&mut b
};
t.disp();
panic!("=== Test ===");
}
It always seems to execute the right destructor, while ignoring the other one. If I tried using a
or b
(like a.disp()
instead of t.disp()
) it correctly errors out saying I might be possibly using uninitialized memory. What surprised me is while panic
king, it always runs the right destructor (printing the expected string) no matter what the value of i
is.
How does this happen? If the runtime can determine which destructor to run, should the part about memory mandatorily needing to be initialized for types with Drop
implemented be removed from documentation of mem::uninitialized()
as linked above?