You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Rust FFI场景下如何用*mut指针与长度正确释放数组?

Rust FFI场景下RawCppPtr数组的释放实现评审

请勿将此问题标记为无std下将*mut u8转为&[u8]的重复问题,我需要对自己的实现思路进行评审。

问题背景

考虑如下C++代码,释放指针数组需要执行:

void foo() {
    T ** array_of_pointers = ...;
    size_t size_of_array = ...;
    for (int i = 0; i < size_of_array; i++) {
        delete array_of_pointers[i];
    }
    delete [] array_of_pointers;
}

在Rust中我也构建了类似的array_of_pointers结构,用于模拟FFI代码场景(具体细节已省略以简化问题)。

我的实现代码

定义了RawCppPtr作为T*(非数组)的包装,RawCppPtrArr作为T**(T*的数组)的包装。此处假设T为String,通过gen_cpp_string创建String并放入Vec<RawCppPtr>,再将其转为*mut [RawCppPtr](包含数组长度的胖指针),最终转为*mut RawCppPtr(指向数组首元素的瘦指针,是否正确?)。

pub struct RawCppPtr {
    pub ptr: *mut std::os::raw::c_void,
    pub type_: u64,
}

impl Drop for RawCppPtr {
    fn drop(&mut self) {
        assert_eq!(self.type_, 1);
        unsafe {
            drop(Box::<Vec<u8>>::from_raw(self.ptr as *mut Vec<u8>));
        }
    }
}

extern "C" fn gen_cpp_string(s: &[u8]) -> RawCppPtr {
    let str = Box::new(Vec::from(s));
    let ptr = Box::into_raw(str);
    RawCppPtr {
        ptr: ptr as *mut _,
        type_: 1,
    }
}


unsafe impl Send for RawCppPtrArr {}

pub struct RawCppPtrArr {
    pub inner: *mut RawCppPtr,
    pub len: u64,
}

impl Drop for RawCppPtrArr {
    fn drop(&mut self) {
        unsafe {
            let len = self.len;
            // Delete all `T**`
            for i in 0..len {
                let i = i as usize;
                let inner_i = self.inner.add(i);
                drop(inner_i);
            }
            // Delete `T*`
            drop(self.inner);
            self.inner = std::ptr::null_mut();
            self.len = 0;
        }
    }
}

fn main() {
    let len = 10;
    let mut v: Vec<RawCppPtr> = vec![];

    for i in 0..len {
        let s = format!("s{}", i);
        v.push(gen_cpp_string(s.as_bytes()));
    }

    let box_v = v.into_boxed_slice();
    // Convert from *mut [RawCppPtr] tp *mut RawCppPtr
    let ptr_va = Box::into_raw(box_v);

    println!("va {}", std::mem::size_of_val(&(ptr_va))); // 16 which means a fat pointer
    let ptr_v = ptr_va as *mut RawCppPtr;
    let cpp_ptr_arr = RawCppPtrArr {
        inner: ptr_v,
        len: len as u64,
    };

    println!("v {}", std::mem::size_of_val(&(ptr_v))); // 8 which means a thin pointer
    drop(cpp_ptr_arr);
}

当前问题与疑问

我认为当前代码存在内存泄漏:所有String已被释放,但RawCppPtr数组未被正确释放,应该释放*mut [RawCppPtr]而非*mut RawCppPtr来释放该数组。

我想了解如何通过*mut RawCppPtr与原*mut [RawCppPtr]的长度来正确释放此数组。注意:由于是FFI代码,C++没有胖指针,因此我不想使用*mut [RawCppPtr]。


更新与补充

经过搜索,我发现from_raw_parts系列函数可能有用,但不确定这是否是最佳实践,同时也需要对我的整体实现思路进行评审。

补充FFI场景说明:在我的程序中,Rust知道何时释放RawCppPtr,但不知道如何释放(因为它由C创建),因此Rust释放RawCppPtr时会调用FFI函数,由C端通过类型检查来完成释放。例如RawCppPtr作为Rust持有的上下文,但仅对C有意义,当Rust不再需要调用C时就会释放它。


内容的提问来源于stack exchange,提问作者calvin

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.07 05:55:16