Когда можно продлить срок действия ссылок на арены? - PullRequest
1 голос
/ 03 июня 2019

У меня есть структура, которая использует 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 .

1 Ответ

4 голосов
/ 03 июня 2019

Безопасно ли продлевать время жизни ссылки на арену до тех пор, пока она ограничена временем жизни основной структуры?

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.

...