我如何泄漏内存,然后确保它的清理才是真正的问题.以下显然不起作用?

你可能会问自己"为什么有人想这么做?"因为我使用的 crate 需要strstatic的生命周期 .

use std::mem::ManuallyDrop;
use std::mem;
    
fn main(){
    fn string_to_static_str(s: String) -> &'static str {
       Box::leak(format!("{}", s).into_boxed_str())
    }

    let string: &'static str = string_to_static_str(String::from("hello"));
    
    ManuallyDrop::into_inner(ManuallyDrop::new(string));

    mem::forget(string);

    println!("{}", string);
}

推荐答案

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);
        }
    }
}

Rust相关问答推荐

如何在Rust中为具有多个数据持有者的enum变体编写文档 comments ?

使用Rust s serde_json对混合数据类型进行优化'

Rust TcpStream不能在读取后写入,但可以在不读取的情况下写入.为什么?

当一个箱子有自己的依赖关系时,两个人如何克服S每箱1库+n箱的限制?

如何提高自定义迭代器的`extend`性能

在自定义序列化程序中复制serde(With)的行为

在Rust中判断编译时是否无法访问

如何go 除多余的(0..)在迭代中,当它不被使用时?

当发送方分配给静态时,Tokio MPSC关闭通道

有没有一种方法可以创建一个闭包来计算Rust中具有随机系数的n次多项式?

如何执行数组文字的编译时串联?

这个不安全的 Rust 代码有什么问题,所以它可以在 Windows 上运行,但不能在 Ubuntu 上运行?

仅当函数写为闭包时才会出现生命周期错误

内部值发生变化时 Rc 的行为

为什么在 rust 中删除 vec 之前应该删除元素

使用部分键从 Hashmap 中检索值

在 Traits 函数中设置生命周期的问题

为什么我可以在没有生命周期问题的情况下内联调用 iter 和 collect?

编写 TOML 文件以反序列化为 struct 中的枚举

如何在 Rust 的内置函数上实现特征?