эффективный вызов неуправляемого метода, принимающего неуправляемые объекты в качестве параметров из управляемого кода - PullRequest
3 голосов
/ 14 апреля 2011

У меня есть следующий сценарий.Управляемый код будет инициализировать множество объектов класса, который является оберткой вокруг неуправляемой структуры.Есть два подхода, которые я могу сделать для этого.Один из них - иметь упаковщик управляемого класса, который просто имеет указатель на неуправляемый объект.Другой - иметь полноценный управляемый класс и создавать неуправляемый объект, когда требуется вызвать неуправляемые методы.Я предоставил оба метода ниже.Мне сказали, что если я использую подход 1 (имеющий указатель на неуправляемый объект), у GC будет много проблем, зная о неуправляемой части, и лучше сделать подход 2. Кто-нибудь скажет мне, что лучше, или если естьэто какой-то другой подход, который даже лучше.Моя проблема с подходом 2 заключается в том, что при каждом вызове неуправляемого метода происходит копирование туда и сюда.Я не уверен, что проблема GC перевешивает ее.

EDIT - первый подход имеет класс ref, а второй - класс значений.Вторая причина заключается в том, что значение может быть более эффективно добавлено в списки

В неуправляемых:

struct A_UNMANAGED
{
    int a;
    int b[20];
};

void GetData(A_UNMANAGED& a); // populates A

В управляемых (первый подход)

public ref class A_MANAGED
{
    A_UNMANGED* ap;

public:
    property System::UInt32 a
    {
        System::UInt32 get() { return ap->a; }
        void set(System::UInt32 value) { ap->a = value; }
    }

    property array<System::UInt32>^ b
    {
        array<System::UInt32>^ get() { return ap->b; }
        void set(array<System::UInt32>^ value) { b = value; } // assume this copy works
    }

internal:
    void GetData()
    {
        GetData(ap);
    }
};

В управляемом (Второй подход) (РЕДАКТИРОВАТЬ: обновлено до ссылки. Предположим, что все сборка мусора и создание указателя написано правильно)

public value class A_MANAGED
{
    System::UInt32 a;
    array<System::UInt32>^ b;

public:
    property System::UInt32 a
    {
        System::UInt32 get() { return a; }
        void set(System::UInt32 value) { a = value; }
    }

    property array<System::UInt32>^ b
    {
        array<System::UInt32>^ get() { return b; }
        void set(array<System::UInt32>^ value) { b = value; }
    }

internal:
    void GetUnmanaged(A_UNMANAGED& obj1)
    {
        obj1.a = a; 
        pin_ptr<System::UInt32> bp = &b[0];
        memcpy(obj1.b, bp, 20);
    }

    void GetData()
    {
        A_UNMANAGED obj2;
        GetUnmanaged(obj2);
        GetData(obj2);
        // copy from obj2 to member variables
    }
};

Ответы [ 2 ]

1 голос
/ 14 апреля 2011

Как сказал Ганс, первый способ - это обычный подход (хотя лично я думаю, что P / Invoke будет более кратким в этом конкретном случае ...). Однако ваша A_MANAGED::b реализация не будет работать, что было бы очевидно, если бы вы попытались просто скомпилировать ее. Попробуйте вместо этого:

public ref class A_MANAGED
{
    A_UNMANAGED* ap;

public:
    A_MANAGED() : ap(new A_UNMANAGED() ) { }
    ~A_MANAGED() { this->!A_MANAGED(); }
    !A_MANAGED() { delete ap; ap = nullptr; }

    property int a
    {
        int get() { return ap->a; }
        void set(int value) { ap->a = value; }
    }

    property array<int>^ b
    {
        array<int>^ get()
        {
            using System::Runtime::InteropServices::Marshal;
            array<int>^ arr = gcnew array<int>(20);
            Marshal::Copy(System::IntPtr(ap->b), arr, 0, 20);
            return arr;
        }
        void set(array<int>^ value)
        {
            using System::Runtime::InteropServices::Marshal;
            Marshal::Copy(value, 0, System::IntPtr(ap->b), 20);
        }
    }

internal:
    void GetData()
    {
        ::GetData(*ap);
    }
};

И есть обычное предостережение о возвращении массивов из свойств: это плохая идея. Если вы действительно не хотите поддерживать паритет с открытым интерфейсом неуправляемого класса, b действительно должна быть парой функций set / get, а не свойством.

1 голос
/ 14 апреля 2011

Нет, 1-й фрагмент это каноническим способом. Сборщик мусора только перемещает указатель, но не перемещает указатель на объект. То, что должно быть выделено с помощью malloc () или оператора new, не может быть перемещено.

В противном случае в вашем коде есть несколько серьезных проблем. Похоже, вы не выделяете память для A_UNMANAGED, если GetData () не принимает аргумент по ссылке. GetData () никогда не вызывается. Обычно это должен быть класс ref (не значение ref), чтобы вы могли предоставить деструктор и финализатор для освобождения памяти. Установщик свойства b будет бомбардировать вашу программу с помощью StackOverflowException. Обязательно изучите язык, прежде чем заняться этим проектом.

Проверьте этот ответ для образца кода.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...