什么时候将引用的生命周期延长到 Arenas 是安全的?
When is it safe to extend the lifetime of references into Arenas?
我有一个使用 Arena
:
的结构
struct Foo<'f> {
a: Arena<u64>, // from the typed-arena crate
v: Vec<&'f u64>,
}
将引用的生命周期延长到 arena 中是否安全,只要它受主结构的生命周期约束?
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。
Is it safe to extend the lifetime of a reference into the arena so long as it is bound by the lifetime of the main struct?
Arena
将与 Foo
一起删除,因此,原则上,这个 会 是安全的,但也没有必要,因为 Arena
已经活得够久了。
但是,这并不是您的代码实际执行的操作!生命周期 'f
可能比结构体的生命周期更长——它可以与 v
中的 shortest-lived 引用一样长。例如:
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
之外拥有 Arena
并依靠借用检查器来确保它在仍在使用时不会被丢弃:
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
中的项目一样有效。然而,这也强制了这个事实是真实的!由于没有不安全代码,您可以相信 borrow-checker 这不会触发 UB。
我有一个使用 Arena
:
struct Foo<'f> {
a: Arena<u64>, // from the typed-arena crate
v: Vec<&'f u64>,
}
将引用的生命周期延长到 arena 中是否安全,只要它受主结构的生命周期约束?
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。
Is it safe to extend the lifetime of a reference into the arena so long as it is bound by the lifetime of the main struct?
Arena
将与 Foo
一起删除,因此,原则上,这个 会 是安全的,但也没有必要,因为 Arena
已经活得够久了。
但是,这并不是您的代码实际执行的操作!生命周期 'f
可能比结构体的生命周期更长——它可以与 v
中的 shortest-lived 引用一样长。例如:
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
之外拥有 Arena
并依靠借用检查器来确保它在仍在使用时不会被丢弃:
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
中的项目一样有效。然而,这也强制了这个事实是真实的!由于没有不安全代码,您可以相信 borrow-checker 这不会触发 UB。