有一个提供三个功能的Rust库:
赞:
#[no_mangle]
pub extern "C" fn initialize_vector() -> *mut Vec<f32> {
Box::into_raw(Box::new(Vec::<f32>::new()))
}
#[no_mangle]
pub extern "C" fn push_to_vector(ptr: *mut Vec<f32>, x: f32) -> *mut Vec<f32> {
if ptr.is_null() { return ptr; }
let vector_box = unsafe { Box::from_raw(ptr) };
let mut example_vector = *vector_box;
example_vector.push(x);
Box::into_raw(Box::new(example_vector))
}
#[no_mangle]
pub extern "C" fn sum_vector(ptr: *mut Vec<f32>) -> f32 {
if ptr.is_null() { return 0.0; }
let vector_box = unsafe { Box::from_raw(ptr) };
let example_vector = *vector_box;
return example_vector.iter().sum();
}
initialize_vector
创建一个Vec
并将其包装在Box
中,将原始指针返回给调用者。现在,调用者负责适当释放分配。
push_to_vector
拥有Box<Vec<f32>>
,moves the Vec
out of the Box
的所有权,从而释放了Box
在此过程中分配的内存。然后,它将一个项目添加到向量中,在Box
周围创建一个全新的Vec
(具有关联的分配)并将其返回。
sum_vector
也拥有Box<Vec<f32>>
的所有权,将Vec
从Box
中移出并释放了内存分配。由于Vec
的所有权不会离开该函数,因此Rust将在函数退出时自动释放与Vec
关联的内存。
使用该库的C#代码如下所示:
using System;
using System.Runtime.InteropServices;
internal class Blabla
{
[DllImport("Example")]
unsafe static public extern IntPtr initialize_vector();
[DllImport("Example")]
unsafe static public extern IntPtr push_to_vector(IntPtr ptr, float x);
[DllImport("Example")]
unsafe static public extern float sum_vector(IntPtr ptr);
static public unsafe void Main()
{
IntPtr vec_ptr = initialize_vector();
vec_ptr = push_to_vector(vec_ptr, (float) 2.2);
vec_ptr = push_to_vector(vec_ptr, (float) 3.3);
float result = sum_vector(vec_ptr);
// is the memory allocated for the vector in Rust freed right now?
Console.WriteLine(string.Format("Result: {0}", result));
Console.ReadLine();
}
}
通常,建议使用SafeHandle
来确定DLL函数返回的指针,例如,参见this question或this example。我了解SafeHandle
的目的主要是在某些意外情况发生时,在某些情况下调用析构函数。
由于在调用sum_vector
函数之后不必释放Rust向量,在给定的情况下是否仍然建议使用SafeHandle
,如果可以,如何?还是我可以直接保留代码,一切都很好?