如何将 *const 指针转换为 Vec 并正确丢弃它?

3

询问如何跨越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 _ 数据,所以我不确定该如何继续...
1个回答

13

非常简短的答案是 self.data as *mut u8。但是,让我们详细讨论一下...

首先,警告:

  1. 除非指针最初来自 Vec,否则不要使用 Vec::from_raw_parts。没有保证任意指针与 Vec 兼容,如果您继续操作,可能会在程序中创建巨大的空洞。

  2. 不要释放您不拥有的指针。这样做会导致 双重释放,从而在程序中造成其他大的空洞。

  3. 在重构向量之前,您需要知道向量的 capacity。您的示例结构体仅包含一个 len。只有当 lencapacity 相等时,这才是可接受的。

现在,让我们看看我是否能遵守自己的规则...

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即可。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接