rust - 你如何避免 cast::forget() 在 rust 中的内存泄漏?

标签 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) 不会导致内存泄漏?

最佳答案

如果 t 被允许超出范围,它将被销毁。如果类型有一个带有副作用的析构函数,那就有问题了;例如,假设我们在一个文件上有一个析构函数,它关闭了文件本身包含的文件句柄。这意味着在 swap 调用中,其中一个文件句柄将被关闭,这当然是不可取的。任何 ~T 也有一个析构函数:它释放内存。如果您要立即运行析构函数,内存将被释放,因此您将遇到释放后使用/双重释放错误。

forget(t) 本身不会导致内存泄漏,因为在 forget 内部,它在堆栈上按值获取参数。因此,当它返回时,堆栈内存被释放。如果您忘记了 ~T,那么 ~T 确实会泄漏内存;但这根本不是这种情况下发生的事情,即使你将 T 替换为 ~U,因为语义:t只是暂存空间;就在 cast::forget(t) 调用之前,实际上是不可靠的,因为同一内存由两个拥有的指针寻址;这就是为什么在不运行析构函数的情况下就简单地忘记了这一点。

问题的关键在于,forget 只应在您要移动值的地方使用,因此将运行其析构函数的东西实际上仍然存在。您不应该在任何其他情况下使用它,否则您泄漏内存。

关于rust - 你如何避免 cast::forget() 在 rust 中的内存泄漏?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23233712/

相关文章:

windows - 在磁盘上读取/写入文件时如何限制硬盘磁盘 I/O?

enums - 用 bool 值检查 Rust 枚举的类型?

rust - 元组如何分解为引用?

rust - Rust中的 move 语义是什么?

rust - 如何插入 LinkedList 的 HashMap 解引用迭代器?

rust - 使用函数样式(flat_map等)实现递归迭代器的麻烦,该函数样式可处理错误并产生Result <…>类型的项

polymorphism - 在 Rust 匹配表达式中保持 DRY

rust - 如何将 toml-rs 结果转换为 std::collections::HashMap

rust - 如何使用 Rust 处理浮点异常 (fpe)?

concurrency - 为什么 Mutex 没有解锁?