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