本文简要介绍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将导致双重释放,因为相同的内存由v
和s
处理。 - 调用
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 forget用法及代码示例
- Rust format_args用法及代码示例
- Rust format用法及代码示例
- Rust f32.exp用法及代码示例
- Rust f32.hypot用法及代码示例
- Rust f32.minimum用法及代码示例
- Rust f64.signum用法及代码示例
- Rust f64.sqrt用法及代码示例
- Rust f32.sqrt用法及代码示例
- Rust f32.abs_sub用法及代码示例
- Rust f64.is_finite用法及代码示例
- Rust f32.cos用法及代码示例
- Rust f32.is_sign_positive用法及代码示例
- Rust f32.log10用法及代码示例
- Rust f64.round用法及代码示例
- Rust f32.total_cmp用法及代码示例
- Rust f64.div_euclid用法及代码示例
- Rust f64.hypot用法及代码示例
- Rust f32.from_ne_bytes用法及代码示例
- Rust f32.recip用法及代码示例
- Rust f64.floor用法及代码示例
- Rust f64.log用法及代码示例
- Rust from_u32_unchecked用法及代码示例
- Rust f64.asinh用法及代码示例
- Rust f64.classify用法及代码示例
注:本文由纯净天空筛选整理自rust-lang.org大神的英文原创作品 Function std::mem::forget。非经特殊声明,原始代码版权归原作者所有,本译文未经允许或授权,请勿转载或复制。