我是 Rust 新手,遇到了一个奇怪的问题,程序的成功或失败取决于是否将不安全的 Rust 放入构造函数中。不确定这是否是一个错误,或者我只是在后者中很幸运,或者我只是错过了一些重要的东西。
失败案例:
fn main() {
let mut xc = Bob::default();
let mut xp = Bob::default();
let mut x = Bob::new(Some(&mut xc), Some(&mut xp));
unsafe {
(&mut *x.child.unwrap()).string = String::from("child");
(&mut *xp.child.unwrap()).string = String::from("middle");
}
println!("{:?}", xc);
println!("{:?}", x);
}
#[derive(Debug)]
struct Bob {
child: Option<*mut Bob>,
parent: Option<*mut Bob>,
string: String,
}
impl Bob {
fn new(child: Option<*mut Bob>, parent: Option<*mut Bob>) -> Bob {
let mut this = Bob {
child,
parent,
string: String::from("Hello")
};
if child.is_some(){
unsafe { child.unwrap().as_mut().unwrap().parent = Some(&mut this);}
}
if parent.is_some(){
unsafe { parent.unwrap().as_mut().unwrap().child = Some(&mut this);}
}
this
}
}
impl Default for Bob {
fn default() -> Bob {
Bob {
child: None,
parent: None,
string: String::from("Hello")
}
}
}
输出:
Bob { child: None, parent: Some(0x37b76ff7f8), string: "child" }
Bob { child: Some(0x37b76ff8b8), parent: Some(0x37b76ff8f0), string: "thread 'main' panicked at 'failed printing to stdout: Windows stdio in console mode does not support writing non-UTF-8 byte sequences', library\std\src\io\stdio.rs:1019:9
stack backtrace:
0: std::panicking::begin_panic_handler
at /rustc/8ede3aae28fe6e4d52b38157d7bfe0d3bceef225/library\std\src\panicking.rs:593
1: core::panicking::panic_fmt
at /rustc/8ede3aae28fe6e4d52b38157d7bfe0d3bceef225/library\core\src\panicking.rs:67
2: std::io::stdio::print_to
at /rustc/8ede3aae28fe6e4d52b38157d7bfe0d3bceef225/library\std\src\io\stdio.rs:1019
3: std::io::stdio::_print
at /rustc/8ede3aae28fe6e4d52b38157d7bfe0d3bceef225/library\std\src\io\stdio.rs:1096
4: rust_allocators::main
at .\src\main.rs:14
5: core::ops::function::FnOnce::call_once<void (*)(),tuple$<> >
at /rustc/8ede3aae28fe6e4d52b38157d7bfe0d3bceef225\library\core\src\ops\function.rs:250
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.
error: process didn't exit successfully: `target\debug\rust-allocators.exe` (exit code: 0xc0000374, STATUS_HEAP_CORRUPTION)
Process finished with exit code -1073740940 (0xC0000374)
工作替代方案:
fn main() {
let mut xc = Bob::default();
let mut xp = Bob::default();
let mut x = Bob::new(Some(&mut xc), Some(&mut xp));
xp.child = Some(&mut x);
// unsafe { Some(&mut xp as *mut Bob).unwrap().as_mut().unwrap().child = Some(&mut x);} // ALSO WORKS
unsafe {
(&mut *x.child.unwrap()).string = String::from("child");
(&mut *xp.child.unwrap()).string = String::from("middle");
}
println!("{:?}", xc);
println!("{:?}", x);
}
#[derive(Debug)]
struct Bob {
child: Option<*mut Bob>,
parent: Option<*mut Bob>,
string: String,
}
impl Bob {
fn new(child: Option<*mut Bob>, parent: Option<*mut Bob>) -> Bob {
let mut this = Bob {
child,
parent,
string: String::from("Hello")
};
if child.is_some(){
unsafe { child.unwrap().as_mut().unwrap().parent = Some(&mut this);}
}
//if parent.is_some(){
// unsafe { parent.unwrap().as_mut().unwrap().child = Some(&mut this);}
//}
this
}
}
impl Default for Bob {
fn default() -> Bob {
Bob {
child: None,
parent: None,
string: String::from("Hello")
}
}
}
输出:
Bob { child: None, parent: Some(0x990ecff628), string: "child" }
Bob { child: Some(0x990ecff708), parent: Some(0x990ecff740), string: "middle" }
我希望这两种情况都能起作用。
指向
this
的指针在这里
unsafe { child.unwrap().as_mut().unwrap().parent = Some(&mut this);}
指向一个函数本地变量,一旦你从该函数返回,它就会变成悬空!之后取消引用它就是 UB。