什么时候可以将引用的生存期延长到Arenas?

时间:2019-06-03 02:20:25

标签: rust lifetime unsafe

我有一个使用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

1 个答案:

答案 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。