本文簡要介紹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。非經特殊聲明,原始代碼版權歸原作者所有,本譯文未經允許或授權,請勿轉載或複製。