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

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

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

    //do stuff to foo
}

Тогда в C # я вызываю функцию так:

[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, Тип): «Данные Marshals из неуправляемого блока памяти во вновь выделенный управляемый объект указанного типа». В этом предложении «Маршалл» означает «копировать»? В этом случае мне нужно сохранить (IntPtr pData), а затем передать его в неуправляемый код (в деструкторе MyDataStructure), чтобы я мог выполнить C ++ «delete»?

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

Ответы [ 2 ]

11 голосов
/ 31 января 2009

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

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

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

7 голосов
/ 30 января 2009

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

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

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

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

...