LinkedList::drain_filter::drop 中 DropGuard 的用途是什么?

A.Z*_*.Z. 3 rust

我正在查看 DrainFilter 的 drop 实现,以确保它删除所有剩余元素,并且我注意到它在每个drop(item);. 这个守卫有什么用?除非这个drop(item);电话引起恐慌,否则我看不出它的目的。难道只是为了确保即使发生恐慌也能删除其余的项目吗?为什么不使用catch_unwind?

相关drop impl:

impl<T, F> Drop for DrainFilter<'_, T, F>
where
    F: FnMut(&mut T) -> bool,
{
    fn drop(&mut self) {
        struct DropGuard<'r, 'a, T, F>(&'r mut DrainFilter<'a, T, F>)
        where
            F: FnMut(&mut T) -> bool;

        impl<'r, 'a, T, F> Drop for DropGuard<'r, 'a, T, F>
        where
            F: FnMut(&mut T) -> bool,
        {
            fn drop(&mut self) {
                self.0.for_each(drop);
            }
        }

        while let Some(item) = self.next() {
            let guard = DropGuard(self);
            drop(item);
            mem::forget(guard);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

Cha*_*man 5

是的,这是为了防止析构函数发生恐慌的情况item。该模式在标准库中多次使用(也在外国包中)。

catch_unwind()有两个缺点:

  1. 下降防护装置比 更可优化catch_unwind()。它们几乎总是在快乐的路径上正确优化,而catch_unwind()并非如此。此外,它们在恐慌路径上的成本也较低,因为没有必要resume_unwind()

  2. 双重恐慌。如果当我们处于恐慌之中时另一个元素的析构函数发生恐慌,会发生什么?对于下降防护装置,这是一个硬中止。这与语言的其余部分一致,其中双重恐慌会导致硬中止。然而,对于catch_unwind(),使用简单的方法(catch_unwind()+清理代码+ resume_unwind())这会导致第一个恐慌被忽略,这不是用户可能期望的,并且正确处理这个需要一个 double catch_unwind()