我正在从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()
}
Run Code Online (Sandbox Code Playgroud)
如果我理解正确,.to_vec()将把切片中的数据复制到一个新的Vec,因此仍然需要释放底层内存(因为切片的底层内存在删除时不会被释放).
处理上述问题的正确方法是什么?
Vec取得底层内存的所有权,在释放时Vec释放它吗?我可以创建一个
Vec取得底层内存的所有权,在释放时Vec释放它吗?
不安全,没有.你不能使用Vec::from_raw_parts,除非指针从来到Vec最初(当然,从相同的内存分配器).否则,您将尝试释放分配器不知道的内存; 一个非常糟糕的主意.
我应该在哪里/如何在Rust中释放C函数分配的内存?
一旦你完成它并且不久就完成了.
以上可能/应该改进的其他内容?
slice::from_raw_partsptr::null,而不是ptr::null_mutuse 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() {}
Run Code Online (Sandbox Code Playgroud)
您没有说明为什么需要它作为a 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() {}
Run Code Online (Sandbox Code Playgroud)
也可以看看:
| 归档时间: |
|
| 查看次数: |
1331 次 |
| 最近记录: |