В документации для mem::uninitialized
указывается, почему это опасно/небезопасно использовать эту функцию: вызов drop
в неинициализированной памяти - это поведение undefined.
Итак, этот код должен быть, я считаю, undefined:
let a: TypeWithDrop = unsafe { mem::uninitialized() };
panic!("=== Testing ==="); // Destructor of `a` will be run (U.B)
Однако я написал этот фрагмент кода, который работает в безопасном Rust и, похоже, не страдает от поведения undefined:
#![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 ===");
}
Кажется, что он выполняет правильный деструктор, игнорируя другой. Если я попытался использовать a
или b
(например, a.disp()
вместо t.disp()
), он правильно ошибается, говоря, что, возможно, я могу использовать неинициализированную память. Что меня удивило, когда король panic
, он всегда запускает правильный деструктор (печатает ожидаемую строку) независимо от того, что такое значение i
.
Как это происходит? Если среда выполнения может определить, какой деструктор будет выполняться, должна ли быть удалена часть из памяти, которая должна быть инициализирована для типов с drop
, из документации mem::uninitialized()
, как указано выше?