Желательно ли использовать SafeHandle, когда вызов метода объекта также уничтожает объект? - PullRequest
0 голосов
/ 25 сентября 2018

Существует библиотека 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>>, перемещает Vec из 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, см., Например, этот вопрос или этот пример .Я понимаю, что цель SafeHandle состоит в том, чтобы вызывать деструктор в определенных случаях, когда происходит что-то незапланированное.

Поскольку нет необходимости освобождать вектор Rust после вызова функции sum_vector, все же рекомендуется использовать SafeHandle в данной ситуации, и если да, то как?Или можно просто оставить код как есть и все нормально?

...