mem::forget
不能清除内存.事实上,它的作用恰恰相反,它告诉Rust不要设定一个值.为了清理泄漏的盒子,你需要一些不安全的代码.
免责声明
你可能会问自己"为什么有人想这么做?"因为我使用的 crate 需要一个静态生命周期 的str.
老实说,除非记忆是个问题,否则就别把它清理干净.你将需要不安全的代码来释放它,如果你在程序的最后清理它,那么你真的不会从中获得任何好处.当程序结束时,不管怎样,操作系统都会回收程序的所有内存,而且速度可能会比先删除程序快.
听起来像是你被一个坏箱子困住了,如果它需要一个&'static str
,而你知道它不需要那一辈子.仅在绝对需要'static
的情况下使用生命周期 'static
.
解决方案
下面是你如何创建然后免费的&'static str
.我可能会使用你原来的string_to_static_str
,但我决定改为使用Box::into_raw
,因为Box::leak
不能保证收回价值.另一方面,在使用Box::into_raw
后,您可以通过Box::from_raw
回收一个盒子.
fn to_static_str<S: AsRef<str>>(str: S) -> &'static str {
let boxed = str.as_ref().to_owned().into_boxed_str();
// Use Box::into_raw we can reclaim ownership with from_raw
unsafe { &*Box::into_raw(boxed) }
}
unsafe fn free_static_str(str: &'static str) {
// Take back ownership using unsafe code
let boxed = Box::from_raw(str as *const str as *mut str);
// Not necessary since it would get dropped anyway at the end of the function,
// but it makes the intent more explicit
std::mem::drop(boxed);
}
编辑
这里有一个更安全的方法.与之前的解决方案不同,此解决方案防止双重释放,只允许释放使用此方法创建的值.
use std::ptr::NonNull;
pub struct Reclaimable<T: ?Sized>(NonNull<T>);
impl<T> Reclaimable<T> {
fn new(x: T) -> Self {
Self::from_boxed(Box::new(x))
}
}
impl<T: ?Sized> Reclaimable<T> {
fn from_boxed(x: Box<T>) -> Self {
Reclaimable(NonNull::new(Box::into_raw(x)).unwrap())
}
fn as_ref<'a>(&self) -> &'a T {
unsafe { &*self.0.as_ptr() }
}
unsafe fn reclaim(self) {
unsafe {
Box::from_raw(self.0.as_ptr() as *mut T);
}
}
}