当前位置: 首页>>代码示例 >>用法及示例精选 >>正文


Rust forget用法及代码示例


本文简要介绍rust语言中 Function std::mem::forget 的用法。

用法

pub const fn forget<T>(t: T)

在不运行其析构函数的情况下获取有关该值的所有权和“forgets”。

该值管理的任何资源,例如堆内存或文件句柄,将永远处于无法访问的状态。但是,它不保证指向该内存的指针将保持有效。

  • 如果要泄漏内存,请参阅 Box::leak
  • 如果要获取指向内存的原始指针,请参阅 Box::into_raw
  • 如果你想正确处理一个值,运行它的析构函数,参见 mem::drop

安全性

forget 未标记为 unsafe ,因为 Rust 的安全保证不包括析构函数将始终运行的保证。例如,程序可以使用 Rc 创建引用循环,或调用 process::exit 退出而不运行析构函数。因此,允许 mem::forget 来自安全代码并不会从根本上改变 Rust 的安全保证。

也就是说,泄漏资源(例如内存或 I/O 对象)通常是不可取的。在 FFI 或不安全代码的一些特殊用例中会出现需求,但即便如此,通常还是首选 ManuallyDrop

因为允许忘记一个值,所以您编写的任何unsafe 代码都必须允许这种可能性。您不能返回一个值并期望调用者必然会运行该值的析构函数。

例子

mem::forget 的规范安全使用是规避由 Drop 特征实现的值的析构函数。例如,这将泄漏 File ,即回收变量占用的空间但从不关闭底层系统资源:

use std::mem;
use std::fs::File;

let file = File::open("foo.txt").unwrap();
mem::forget(file);

当底层资源的所有权先前被转移到 Rust 之外的代码时,这很有用,例如通过将原始文件说明符传输到 C 代码。

ManuallyDrop的关系#

尽管mem::forget也可用于传输 memory 所有权,这样做是error-prone。std::mem::ManuallyDrop应该使用。例如,考虑以下代码:

use std::mem;

let mut v = vec![65, 122];
// Build a `String` using the contents of `v`
let s = unsafe { String::from_raw_parts(v.as_mut_ptr(), v.len(), v.capacity()) };
// leak `v` because its memory is now managed by `s`
mem::forget(v);  // ERROR - v is invalid and must not be passed to a function
assert_eq!(s, "Az");
// `s` is implicitly dropped and its memory deallocated.

上面的例子有两个问题:

  • 如果在 String 的构造和 mem::forget() 的调用之间添加更多代码,其中的Panics将导致双重释放,因为相同的内存由 vs 处理。
  • 调用v.as_mut_ptr()并将数据的所有权传递给s后,v值无效。即使一个值刚刚被移动到mem::forget(它不会检查它),某些类型对它们的值有严格的要求,这使得它们在悬空或不再拥有时无效。以任何方式使用无效值,包括将它们传递给函数或从函数返回它们,都会构成未定义的行为,并且可能会破坏编译器所做的假设。

切换到 ManuallyDrop 可以避免这两个问题:

use std::mem::ManuallyDrop;

let v = vec![65, 122];
// Before we disassemble `v` into its raw parts, make sure it
// does not get dropped!
let mut v = ManuallyDrop::new(v);
// Now disassemble `v`. These operations cannot panic, so there cannot be a leak.
let (ptr, len, cap) = (v.as_mut_ptr(), v.len(), v.capacity());
// Finally, build a `String`.
let s = unsafe { String::from_raw_parts(ptr, len, cap) };
assert_eq!(s, "Az");
// `s` is implicitly dropped and its memory deallocated.

ManuallyDrop 强有力地阻止了 double-free 因为我们在执行任何其他操作之前禁用了 v 的析构函数。 mem::forget() 不允许这样做,因为它消耗了它的参数,迫使我们只有在从 v 提取我们需要的任何内容后才调用它。即使在ManuallyDrop 的构造和字符串的构造之间引入了Panics(这在所示的代码中不会发生),它也会导致泄漏而不是双重释放。换句话说,ManuallyDrop 在泄漏方面出错,而不是在(double)丢弃方面出错。

此外,ManuallyDrop 使我们不必在将所有权转移到 s 后进行 “touch” v — 完全避免了与 v 交互以在不运行其析构函数的情况下处理它的最后一步。

相关用法


注:本文由纯净天空筛选整理自rust-lang.org大神的英文原创作品 Function std::mem::forget。非经特殊声明,原始代码版权归原作者所有,本译文未经允许或授权,请勿转载或复制。