Безопасно ли продлевать время жизни ссылки на арену до тех пор, пока она ограничена временем жизни основной структуры?
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.