Rust 何时可以安全地将引用的生命周期延长到竞技场?

Rust 何时可以安全地将引用的生命周期延长到竞技场?,rust,lifetime,unsafe,Rust,Lifetime,Unsafe,我有一个结构,它使用: struct Foo, } 只要引用的生存期受主结构的生存期约束,那么将引用的生存期延长到竞技场中是否安全 impl<'f> Foo<'f> { pub fn bar(&mut self, n: u64) -> Option<&'f u64> { if n == 0 { None } else { let n_ref = un

我有一个结构,它使用:

struct Foo,
}
只要引用的生存期受主结构的生存期约束,那么将引用的生存期延长到竞技场中是否安全

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)
        }
    }
}
impl{
pub fn bar(&mut self,n: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)
        }
    }
}
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!
}
试图假装生命周期比实际生命周期长,这为安全代码中的未定义行为创造了机会


一种可能的修复方法是在
结构
外部拥有
竞技场
,并依靠借用检查器确保其在仍在使用时不会被丢弃:

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)
}
struct Foo Foo{
如果n==0{
没有一个
}否则{
一些(自我a.分配(n))
}
}
}
fn main(){
让arena=arena::new();
设n=1u64;
设v=vec![&n];
让吧;
{
设mut-foo=foo{a:&arena,v};
巴=foo.bar(2);
}
println!(“bar={:?}”,bar);//一些(2)
}
就像您的不安全版本一样,生命周期表示对
Arena
的引用必须至少与
Vec
中的项目一样有效。然而,这也证明了这一事实是真实的!由于没有不安全的代码,您可以相信借阅检查器,这不会触发UB

只要引用的生存期受主结构的生存期约束,那么将引用的生存期延长到竞技场中是否安全

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)
        }
    }
}
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!
}
试图假装生命周期比实际生命周期长,这为安全代码中的未定义行为创造了机会


一种可能的修复方法是在
结构
外部拥有
竞技场
,并依靠借用检查器确保其在仍在使用时不会被丢弃:

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)
}
struct Foo Foo{
如果n==0{
没有一个
}否则{
一些(自我a.分配(n))
}
}
}
fn main(){
让arena=arena::new();
设n=1u64;
设v=vec![&n];
让吧;
{
设mut-foo=foo{a:&arena,v};
巴=foo.bar(2);
}
println!(“bar={:?}”,bar);//一些(2)
}

就像您的不安全版本一样,生命周期表示对
Arena
的引用必须至少与
Vec
中的项目一样有效。然而,这也证明了这一事实是真实的!由于没有不安全的代码,您可以相信借阅检查器,这不会触发UB

取决于许多因素,例如
Arena
超出范围时是否会降低其值?如果是,则无效。如果您查看键入的arena板条箱,它会删除数据。如果您不能存储引用,那么如何将arena用于非平凡代码?人们在使用竞技场时不会遇到这个问题吗?他们不会使用不安全的竞技场,而且借阅检查器会阻止他们做坏事;)(另外,我的任务不是查看板条箱(您没有链接!),而是将您的板条箱视为提出问题的人)。“他们不使用不安全的工具,借阅检查人员正在阻止他们做坏事”——这不是很有帮助。问题是:“我如何解决这个问题?”。回答“不要做X”而不提出备选方案并不能解决我的问题。这是真的。您是否考虑过将其设置为
静态
,例如使用
lazy\u static
板条箱?取决于许多因素,例如
Arena
在超出范围时是否会降低其值?如果是,则无效。如果您查看键入的arena板条箱,它会删除数据。如果您不能存储引用,那么如何将arena用于非平凡代码?人们在使用竞技场时不会遇到这个问题吗?他们不会使用不安全的竞技场,而且借阅检查器会阻止他们做坏事;)(另外,我的任务不是查看板条箱(您没有链接!),而是将您的板条箱视为提出问题的人)。“他们不使用不安全的工具,借阅检查人员正在阻止他们做坏事”——这不是很有帮助。问题是:“我如何解决这个问题?”。回答“不要做X”而不提出备选方案并不能解决我的问题。这是真的。您是否考虑过将其设置为
静态
,例如使用
lazy\u static
板条箱?好的,我了解问题所在。现在,我该如何解决它?如何使用竞技场并将引用存储到竞技场中?我是否重构了我的数据类型(C.F.ReDDIT链接,在这里我考虑了一些选项)?还有别的吗?@indigamer也许你可以在结构之外拥有竞技场,完全避免不安全的代码。我将添加一个示例。嗯,这确实解决了使用Arena的问题。谢谢然而,我遇到了同样的问题,与分配器的
&Arena
相比,它(正确地)需要
&mutstringinterner
。此外,在这个看似安全的API背后,竞技场可能处于多线程状态。好的,我明白问题所在。现在,我该如何解决它?我如何使用竞技场和