[英]What is the preferred unsafe way to extend lifetimes which are correct but not provable?
我有一个最小的竞技场分配器,它展示了这个意图,尽管它没有像真正的竞技场那样为最小化分配/释放进行优化:
#[derive(Clone)]
pub struct Arena(Arc<Mutex<Vec<Box<[u8]>>>>);
impl Arena {
/// Allocate memory of the given size.
pub fn allocate(&self, size: usize) -> &mut [u8] {
let inner = &mut *self.0.lock().unwrap();
let mut new_mem = vec![0u8; size].into_boxed_slice();
let slice = &mut new_mem[..]; // THIS OBVIOUSLY DOESNT WORK
inner.push(new_mem);
slice
}
}
allocate
是唯一的操作,因此我知道我可以安全地引用new_mem
中包含的内存,其生命周期与&self
相同,因为我不提供任何允许装箱内存成为别名的操作,我知道因为内存块是装箱的,即使它存储的向量必须重新分配以添加额外的块,它也不会移动。
我也不知道如何安全地告诉编译器对内存块的引用是安全的。 使用&mut new_mem[..]
失败,因为编译器认为我在尝试将new_mem
移动到push
中的向量中时借用了它。 我可以颠倒顺序并在&mut inner.last().unwrap()[..]
之后执行push
,但这也失败了,因为编译器认为该引用归互斥锁所有。
这意味着要告诉编译器这个借用是可以的,我需要做一些unsafe
的事情来创建一个比正常借用在这种情况下产生的生命周期更长的引用。
我知道延长此寿命的两种方法:
std::mem::transmute
:
let slice = { // Strongly-typed line to make sure we aren't accidentally starting from a pointer to // the box itself by accident. let slice: &mut [u8] = &mut new_mem[..]; unsafe { mem::transmute(slice) } };
取消引用原始指针:
let slice = { // Strongly-typed line to make sure we aren't accidentally starting from a pointer to // the box itself by accident. let slice: &mut [u8] = &mut new_mem[..]; let ptr: *mut _ = slice; unsafe { &mut *ptr } };
这些选项中的任何一个都有什么特别的优势吗? 例如,是否有一类错误可能在一个选项中出现而在另一个选项中是不可能的,或者更难犯? 还有其他具有不同优势的方法吗? 还是所有选项都差不多?
对于错误类别,我特别想知道是否存在类型推断错误可能发生在一个错误中,而另一个错误则不可能发生。 显然, transmute
可以转换为具有相同大小的任何东西,并且原始指针允许转换为任何类型而不管大小,但我想知道在没有as
转换的情况下,指针的类型推断是否会受到更多限制。
这个怎么样?
impl Arena {
/// Allocate memory of the given size.
pub fn allocate(&self, size: usize) -> &mut [u8] {
let inner = &mut *self.0.lock().unwrap();
let mut new_mem = vec![0u8; size].into_boxed_slice();
let mem_ptr: *mut u8 = new_mem.as_mut_ptr();
let slice = unsafe { std::slice::from_raw_parts_mut(mem_ptr, size) };
inner.push(new_mem);
slice
}
}
我不知道利弊,但我就是这样做的。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.