В документации для mem::uninitialized
указано, почему это опасно/небезопасно для использования этой функции: вызов drop
в неинициализированной памяти является неопределенным поведением.Как Rust знает, следует ли запускать деструктор во время стека?
Так что этот код должен быть, как мне кажется, не определено:
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
король, он всегда запускает правый деструктор (печатает ожидаемую строку) независимо от того, что такое значение i
.
Как это происходит? Если среда выполнения может определить, какой деструктор будет запущен, должна ли быть извлечена часть из памяти, которая обязательно должна быть инициализирована для типов с Drop
, из документации mem::uninitialized()
, как указано выше?
Как Раймонд Чен любит указывать, потому что «неопределенное поведение» означает «что-либо может случиться и все еще быть действительным», * один из действительных последствий заключается в том, что все должно работать правильно. * –
A.K.A. «ошибочное отсутствие доказательств для доказательства отсутствия» - в печально известном «Черном лебеде». – mickeyf
@mickeyf @MasonWheeler: Извините, если я не понял вас, но в Rust я ожидал бы, если бы я не использовал какой-либо «небезопасный» код (которого я не делаю в основном примере выше), что бы наблюдалось (даже в первом запуске) в значительной степени четко определено - это будет (одна из) главная причина, по которой многие выбрали бы Rust в первую очередь (по крайней мере, я сделал). – ustulation