如何使用cast :: forget()防止内存泄漏?

时间:2014-04-23 02:25:00

标签: rust

标准库中有一些代码如下:

/**
 * Swap the values at two mutable locations of the same type, without
 * deinitialising or copying either one.
 */
#[inline]
pub fn swap<T>(x: &mut T, y: &mut T) {
    unsafe {
        // Give ourselves some scratch space to work with
        let mut t: T = uninit();

        // Perform the swap, `&mut` pointers never alias
        ptr::copy_nonoverlapping_memory(&mut t, &*x, 1);
        ptr::copy_nonoverlapping_memory(x, &*y, 1);
        ptr::copy_nonoverlapping_memory(y, &t, 1);

        // y and t now point to the same thing, but we need to completely forget `t`
        // because it's no longer relevant.
        cast::forget(t);
    }
}

事实上,这会创建临时的临时空间,然后忘记它。模式出现了几次。

根据文档intrinsics::forget()取得所有权但不会破坏某个值,从而有效地忘记了目标。

两个非常简单的问题:

  1. 为什么这是必要的,而不是让t超出范围并被销毁?

  2. 为什么forget(t)不会导致内存泄漏?

1 个答案:

答案 0 :(得分:3)

如果t被允许超出范围,它将被销毁。如果类型具有带有副作用的析构函数,则会出现问题;例如,假设我们在文件上有一个析构函数,用于关闭包含在其中的文件句柄。这意味着在swap调用时,其中一个文件句柄将被关闭,这当然是不可取的。任何~T都有一个析构函数:它释放内存。如果你要立即运行析构函数,内存将被释放,所以你将有一个免费后使用/双免费的bug。

forget(t)本身不会导致内存泄漏,因为在forget内,它在堆栈上按值获取其参数。因此,当它返回时,堆栈存储器被释放。如果你忘了~T,那~T确实会泄漏记忆;但由于语义原因,即使您将T作为~U进行交换,这也不是在这种情况下发生的事情:t只是划痕空间;就在cast::forget(t)调用之前,实际上存在不健全性,因为相同的内存由两个拥有的指针解决;这就是为什么一个人在没有运行析构函数的情况下被遗忘的原因。

问题的关键是forget只应该用于移动值的地方,因此运行其析构函数的东西确实仍然存在。您不应该在任何其他情况下使用它,或者可以泄漏内存。

相关问题