首页 文章

从C数组指针创建Rust中的Vec并安全地释放它?

提问于
浏览
2

我正在从Rust调用一个C函数,它将一个空指针作为一个参数,然后分配一些内存来指向它 .

什么是有效(即避免不必要的副本)和安全(即避免内存泄漏或段错误)的正确方法是将数据从C指针转换为 Vec

我有类似的东西:

extern "C" {
    // C function that allocates an array of floats
    fn allocate_data(data_ptr: *mut *const f32, data_len: *mut i32);
}

fn get_vec() -> Vec<f32> {
    // C will set this to length of array it allocates
    let mut data_len: i32 = 0;

    // C will point this at the array it allocates
    let mut data_ptr: *const f32 = std::ptr::null_mut();

    unsafe { allocate_data(&mut data_ptr, &mut data_len) };

    let data_slice = unsafe { slice::from_raw_parts(data_ptr as *const f32, data_len as usize) };
    data_slice.to_vec()
}

如果我理解正确, .to_vec() 会将切片中的数据复制到新的 Vec 中,因此仍需要释放底层内存(因为切片的底层内存已经丢失了) .

处理上述问题的正确方法是什么?

  • 我可以创建一个 Vec ,它取得底层内存的所有权,当释放_1274205时释放它吗?

  • 如果不是,在Rust中我应该释放C函数分配的内存?

  • 以上可能/应该改进的其他内容?

1 回答

  • 8

    我可以创建一个Vec来取得底层内存的所有权,当Vec被释放时它会被释放吗?

    不安全,没有 . 你 must not 使用 Vec::from_raw_parts 除非指针最初来自 Vec (好吧,来自同一个内存分配器) . 否则,您将尝试释放分配器不知道的内存;一个非常糟糕的主意 .

    在哪里/如何在Rust中我应该释放C函数分配的内存?

    一旦你完成它并且不久就完成了 .

    上面可能/应该改进的其他任何事情?

    • 调用 slice::from_raw_parts 时无需强制转换指针

    • 变量上不需要显式类型

    • 使用 ptr::null ,而不是 ptr::null_mut

    • 执行NULL指针检查

    • 检查长度是否定的

    use std::{ptr, slice};
    
    extern "C" {
        fn allocate_data(data_ptr: *mut *const f32, data_len: *mut i32);
        fn deallocate_data(data_ptr: *const f32);
    }
    
    fn get_vec() -> Vec<f32> {
        let mut data_ptr = ptr::null();
        let mut data_len = 0;
    
        unsafe {
            allocate_data(&mut data_ptr, &mut data_len);
            assert!(!data_ptr.is_null());
            assert!(data_len >= 0);
    
            let v = slice::from_raw_parts(data_ptr, data_len as usize).to_vec();
            deallocate_data(data_ptr);
    
            v
        }
    }
    
    fn main() {}
    

    您没有说明为什么需要它作为 Vec ,但如果您永远不需要更改大小,您可以创建自己的类型,可以作为切片取消引用并在适当时删除数据:

    use std::{ptr, slice};
    
    extern "C" {
        fn allocate_data(data_ptr: *mut *const f32, data_len: *mut i32);
        fn deallocate_data(data_ptr: *const f32);
    }
    
    struct CVec {
        ptr: *const f32,
        len: usize,
    }
    
    impl std::ops::Deref for CVec {
        type Target = [f32];
    
        fn deref(&self) -> &[f32] {
            unsafe { slice::from_raw_parts(self.ptr, self.len) }
        }
    }
    
    impl Drop for CVec {
        fn drop(&mut self) {
            unsafe { deallocate_data(self.ptr) };
        }
    }
    
    fn get_vec() -> CVec {
        let mut ptr = ptr::null();
        let mut len = 0;
    
        unsafe {
            allocate_data(&mut ptr, &mut len);
            assert!(!ptr.is_null());
            assert!(len >= 0);
    
            CVec {
                ptr,
                len: len as usize,
            }
        }
    }
    
    fn main() {}
    

    也可以看看:

相关问题