當前位置: 首頁>>代碼示例 >>用法及示例精選 >>正文


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