Нужно ли удалять структуры, маршалированные через Marshal.PtrToStructure в неуправляемом коде?

У меня есть код С++:

extern "C" __declspec(dllexport) VOID AllocateFoo(MY_DATA_STRUCTURE** foo)
{
    *foo = new MY_DATA_STRUCTURE;

    //do stuff to foo
}

Затем в С# я вызываю функцию таким образом:

[DllImport("MyDll.dll")]
static extern void AllocateFoo(out IntPtr pMyDataStruct);

...

MyDataStructure GetMyDataStructure()
{
    IntPtr pData;
    ManagedAllocateFooDelegate(out pData);

    MyDataStructure foo = (MyDataStructure)Marshal.PtrToStructure(pData, typeof(MyDataStructure));
    return foo;
}

Где MyDataStructure - это структура (не класс), которая соответствует MY_DATA_STRUCTURE, и члены сортируются соответствующим образом.

Итак, вопросы: нужно ли хранить pData, а затем снова выпускать его в неуправляемом коде, когда MyDataStructure GC'd? MSDN говорит для Marshal.PtrToStructure(IntPtr, Type): "Данные маршалов из неуправляемого блока памяти в новый выделенный управляемый объект указанного типа". В этом предложении "Маршалл" означает "копия"? В этом случае мне нужно будет сохранить (IntPtr pData), а затем передать его неуправляемому коду (в деструкторе MyDataStructure), чтобы я мог выполнить "удаление" на С++?

Я искал, но я не могу найти достаточно явный ответ для этого.

Ответ 1

Как сказал Эрик, маршал действительно означает копию, но я не думаю, что он ответил на главный вопрос вашего вопроса.

Нужно ли удерживать указатель на pData, пока MyDataStructure не будет GCed? Нет.

После маршалинга ваш экземпляр MyDataStructure, foo, содержит копию структуры, на которую указывает pData. Вам больше не нужно держать pData. Чтобы избежать утечки памяти, вы должны передать эту pData в другую неуправляемую функцию, которая удалит ее, и это можно сделать сразу после маршалинга, независимо от того, как долго вы держитесь за экземпляр MyDataStructure.

Ответ 2

Да, в этом случае Маршалл означает копию; таким образом, вам необходимо освободить память в неуправляемом коде. Все вызовы PtrToStructure читаются в количестве байтов, обозначенных размером структуры назначения MyDataStructure из ячейки памяти, на которую указывает pData.

Детали зависят от того, как выглядит "MyDataStructure" (используете ли вы какие-либо атрибуты FieldOffset или StructLayout в MyDataStructure), но конечным результатом является то, что возврат из PtrToStructure является копией данных.

Как GBegen указывает его ответ, я не ответил на главный вопрос ваш вопрос. Да, вам нужно будет удалить неуправляемую копию вашей структуры в неуправляемом коде, но нет, вам не нужно держать pData - вы можете удалить неуправляемую копию, как только завершится вызов PtrToStructure.

PS: Я отредактировал свой пост, чтобы содержать эту информацию, чтобы объединить ответы в одно сообщение - если кто-то подтвердит этот ответ, пожалуйста, поддержите ответ GBegen также за его вклад.