我正在 Rust 中创建一个双向图,父指针是 Rust 借用规则的一个明显问题,因此我使用了理论上安全的原始指针,因为父指针拥有子指针并且不能在子指针之前删除。我(在我脑海中)唯一的问题是图表何时移动。如果图形移动,所有父指针都应该无效,因为它们指向图形的旧位置。
但是通过示例测试向我展示了不同的结果。不仅旧指针仍然有效,调试器还在“寄存器>有效地址”中显示一个新条目,该条目将旧指针映射到新位置。 我的测试代码:
fn main() -> Result<()> {
let m = test();
println!("MT:{}, IT:{}, PTR_MT:{}", m.j, m.inner.i, unsafe {(*m.inner.parent).j});
Ok(())
}
fn test() -> Box<MyType> {
let mut mytype = MyType { inner: MyInnerType { parent: std::ptr::null_mut(), i: 5 }, j:69 };
println!("MT:{}, IT:{}", mytype.j, mytype.inner.i);
mytype.inner.parent = &mut mytype;
Box::new(mytype)
}
struct MyType {
inner: MyInnerType,
j:i32
}
struct MyInnerType {
parent: *mut MyType,
i:i32
}
此行为是否已定义并且我可以依赖它工作吗?
不,这不安全。它是不健全的并且表现出未定义的行为。 “程序按预期运行”是一种可能的结果,但不是唯一的结果。
Box::new(mytype)
将 mytype
移动到堆分配中,这不是 UB。然而,稍后评估 *m.inner.parent
会导致 UB,因为指针目标已移动。
您通常应该避免在 Rust 中使用原始指针,除非您要在它们之上实现安全抽象,或者您正在使用 FFI 并且如果没有它们就无法完成您需要的任务。