我有一个使用Arena
的结构:
struct Foo<'f> {
a: Arena<u64>, // from the typed-arena crate
v: Vec<&'f u64>,
}
将引用的生存期延长到竞技场中是否安全,只要它受主结构的生存期约束?
impl<'f> Foo<'f> {
pub fn bar(&mut self, n: u64) -> Option<&'f u64> {
if n == 0 {
None
} else {
let n_ref = unsafe { std::mem::transmute(self.a.alloc(n)) };
Some(n_ref)
}
}
}
有关更多背景信息,请参见此Reddit comment。
答案 0 :(得分:4)
将引用的生存期延长到竞技场中是否安全,只要它受主结构的生存期约束?
Arena
将与Foo
一起删除,因此,从原理上讲,此将是安全的,但由于Arena
<他们已经活了足够长的时间了。
但是,这不是您的代码实际上在做什么!生存期'f
可以比该结构的生存期更长-它可以与v
中最短生存期的引用一样长。例如:
fn main() {
let n = 1u64;
let v = vec![&n];
let bar;
{
let mut foo = Foo { a: Arena::new(), v };
bar = foo.bar(2);
// foo is dropped here, along with the Arena
}
// bar is still useable here because 'f is the full scope of `n`
println!("bar = {:?}", bar); // Some(8021790808186446178) - oops!
}
试图假装寿命比实际寿命更长,这为使用安全代码的未定义行为创造了机会。
一种可能的解决方法是在Arena
之外拥有struct
,并依靠借阅检查器来确保它在使用时未被丢弃:
struct Foo<'f> {
a: &'f Arena<u64>,
v: Vec<&'f u64>,
}
impl<'f> Foo<'f> {
pub bar(&mut self, n: u64) -> Option<&'f u64> {
if n == 0 {
None
} else {
Some(self.a.alloc(n))
}
}
}
fn main() {
let arena = Arena::new();
let n = 1u64;
let v = vec![&n];
let bar;
{
let mut foo = Foo { a: &arena, v };
bar = foo.bar(2);
}
println!("bar = {:?}", bar); // Some(2)
}
就像您的不安全版本一样,生存期表示对Arena
的引用必须至少与Vec
中的项目一样有效。但是,这也证明这个事实是正确的!由于没有不安全的代码,因此您可以相信借位检查器不会触发UB。