在询问如何跨越FFI边界释放内存后,Rust Reddit上的某人建议我不要将结构体包装在Box
中,而是可以使用Vec :: from_raw_parts
从以下结构体构造向量,并且这可以安全地删除:
#[repr(C)]
pub struct Array {
data: *const c_void,
len: libc::size_t,
}
然而,
from_raw_parts
似乎需要 *mut _
数据,所以我不确定该如何继续...非常简短的答案是 self.data as *mut u8
。但是,让我们详细讨论一下...
首先,警告:
除非指针最初来自 Vec
,否则不要使用 Vec::from_raw_parts
。没有保证任意指针与 Vec
兼容,如果您继续操作,可能会在程序中创建巨大的空洞。
不要释放您不拥有的指针。这样做会导致 双重释放,从而在程序中造成其他大的空洞。
在重构向量之前,您需要知道向量的 capacity。您的示例结构体仅包含一个 len
。只有当 len
和 capacity
相等时,这才是可接受的。
现在,让我们看看我是否能遵守自己的规则...
extern crate libc;
use std::mem;
#[repr(C)]
pub struct Array {
data: *const libc::c_void,
len: libc::size_t,
}
// Note that both of these methods should probably be implementations
// of the `From` trait to allow them to participate in more places.
impl Array {
fn from_vec(mut v: Vec<u8>) -> Array {
v.shrink_to_fit(); // ensure capacity == size
let a = Array {
data: v.as_ptr() as *const libc::c_void,
len: v.len(),
};
mem::forget(v);
a
}
fn into_vec(self) -> Vec<u8> {
unsafe { Vec::from_raw_parts(self.data as *mut u8, self.len, self.len) }
}
}
fn main() {
let v = vec![1, 2, 3];
let a = Array::from_vec(v);
let v = a.into_vec();
println!("{:?}", v);
}
请注意,我们不需要显式地丢弃Vec
,因为Vec
的正常Drop
实现会起作用。我们只需要确保正确构造Vec
即可。