pub const fn forget<T>(t: T)
Expand description
获取所有权和 “forgets” 值,而不运行其析构函数。
该值管理的任何资源 (例如堆内存或文件句柄) 将永远处于无法访问的状态。但是,它不能保证指向该内存的指针将保持有效。
- 如果要泄漏内存,请参见
Box::leak
。 - 如果要获取内存的裸指针,请参见
Box::into_raw
。 - 如果要正确处理某个值,请运行其析构函数,请参见
mem::drop
。
Safety
forget
没有标记为 unsafe
,因为 Rust 的安全保证不包括析构函数将始终运行的保证。
例如,程序可以使用 Rc
创建引用循环,或调用 process::exit
退出而不运行析构函数。
因此,从安全代码允许 mem::forget
不会从根本上改变 Rust 的安全保证。
也就是说,通常不希望泄漏诸如内存或 I/O 对象之类的资源。
在某些特殊的用例中,对于 FFI 或不安全代码提出了需求,但即使这样,通常还是首选 ManuallyDrop
。
因为允许忘记一个值,所以您编写的任何 unsafe
代码都必须允许这种可能性。您不能返回值,并且期望调用者一定会运行该值的析构函数。
Examples
mem::forget
的规范安全使用是为了避免 Drop
trait 实现的值的析构函数。例如,这将泄漏 File
,即
回收变量占用的空间,但不要关闭底层系统资源:
use std::mem;
use std::fs::File;
let file = File::open("foo.txt").unwrap();
mem::forget(file);
Run当底层资源的所有权先前已转移到 Rust 之外的代码时 (例如,通过将原始文件描述符传输到 C 代码),这很有用。
与 ManuallyDrop
的关系
虽然 mem::forget
也可以用于转移 内存 所有权,但是这样做很容易出错。
应改用 ManuallyDrop
。例如,考虑以下代码:
use std::mem;
let mut v = vec![65, 122];
// 使用 `v` 的内容构建 `String`
let s = unsafe { String::from_raw_parts(v.as_mut_ptr(), v.len(), v.capacity()) };
// 泄漏 `v`,因为它的内存现在由 `s` 管理
mem::forget(v); // 错误 - v 无效,不得将其传递给函数
assert_eq!(s, "Az");
// `s` 被隐式丢弃,并释放其内存。
Run上面的示例有两个问题:
- 如果在
String
的构造与mem::forget()
的调用之间添加了更多代码,则其中的 panic 将导致双重释放,因为v
和s
均处理同一内存。 - 调用
v.as_mut_ptr()
并将数据所有权传输到s
之后,v
值无效。 即使将值仅移动到mem::forget
(不会检查它),某些类型对其值也有严格的要求,以使它们在悬垂或不再拥有时无效。 以任何方式使用无效值,包括将它们传递给函数或从函数中返回它们,都构成未定义的行为,并且可能会破坏编译器所做的假设。
切换到 ManuallyDrop
可以避免两个问题:
use std::mem::ManuallyDrop;
let v = vec![65, 122];
// 在将 `v` 解开为原始零件之前,请确保它不会丢弃掉!
let mut v = ManuallyDrop::new(v);
// 现在解开 `v`。这些操作不能 panic,因此不会有泄漏。
let (ptr, len, cap) = (v.as_mut_ptr(), v.len(), v.capacity());
// 最后,构建一个 `String`。
let s = unsafe { String::from_raw_parts(ptr, len, cap) };
assert_eq!(s, "Az");
// `s` 被隐式丢弃,并释放其内存。
RunManuallyDrop
强大地防止双重释放,因为我们在做任何其他事情之前禁用了 v
的析构函数。
mem::forget()
不允许这样做,因为它消耗了它的参数,迫使我们只有在从 v
中提取我们需要的任何东西后才能调用它。
即使在 ManuallyDrop
的构建与字符串的构建之间引入了 panic (这在所示的代码中不能发生),也将导致泄漏,而不是双重释放。
换句话说,ManuallyDrop
在泄漏的一侧发生错误,而不是在 (两次) 丢弃的一侧发生错误。
同样,ManuallyDrop
避免了在将所有权转让给 s
之后必须使用 “touch” v
的情况-完全避免了与 v
交互以处置它而不运行其析构函数的最后一步。