我正在从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
来获取底层内存的所有权,当Vec
被释放时,它会被释放吗?答案 0 :(得分:8)
我可以创建一个
Vec
来获取底层内存的所有权,当Vec
被释放时会被释放吗?
不安全,没有。除非指针最初来自Vec::from_raw_parts
(好,来自同一个内存分配器),否则一定不能使用Vec
。否则,你会尝试释放你的分配器不知道的记忆;一个非常糟糕的主意。
在Rust中我应该如何释放C函数分配的内存?
一旦你完成它并且不久就完成了。
以上可能/应该改进的其他内容?
slice::from_raw_parts
ptr::null
,而不是ptr::null_mut
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() {}
另见: