Неуправляемый экземпляр структуры в управляемом классе - PullRequest
1 голос
/ 26 мая 2010

У меня довольно специфическая проблема, с которой я боролся в течение нескольких дней.

Я использую нативный C ++, один из методов переносит ptr в структуру, содержащую массив символов фиксированного размера.

например.

struct userData {
    char data1[10];
    char data2[10];
};

метод:

short AddItem(long id, userData* data);

Я пытаюсь вызвать этот вызов из Managed VC ++, но мне нужен экземпляр userData, который я могу хранить в своем управляемом классе.

Может кто-нибудь помочь с этим?

Спасибо

Ответы [ 3 ]

3 голосов
/ 26 мая 2010

Я использую один из следующих двух контейнеров, когда предпочтительным является дружественное взаимодействие со сборщиком мусора:

template<typename T> ref class GcPlainPtr sealed {
    T*  ptr;
public:
    GcPlainPtr(T*ptr): ptr(ptr) { GC::AddMemoryPressure(sizeof(T)); }

    !GcPlainPtr() { 
        GC::RemoveMemoryPressure(sizeof(T)); 
        delete ptr; ptr = nullptr; 
    }

    ~GcPlainPtr() { this->!GcPlainPtr(); } //mostly just to avoid C4461

    T* get() {return ptr;}

    static T* operator->(GcPlainPtr<T>% gcPtr) { return gcPtr.ptr;}
    static operator T*(GcPlainPtr<T>% gcPtr) { return gcPtr.ptr; }
};

Предыдущий контейнер выглядит достаточно для ваших нужд. Вы можете использовать его следующим образом:

ref class MyManagedClass {
    GcPlainPtr<userData> myUserData;

    MyManagedClass(...bla...) 
        : myUserData(new userData(...)) 
        , ... 
    {...}

    AnotherMethod() {
        std::cout << myUserData->data1 << '\n';
        AddItem(1, myUserData.get());
    }
}

Преимущество предыдущего подхода состоит в том, что даже если вы забудете избавиться от объектов, нагрузка на память будет разумно обновлена, так что сбор мусора будет происходить с соответствующей частотой.

Если вам известен размер элемента данных, который вы распределяете строго, но это не просто прямой размер (т. Е. Собственная структура или класс выделяет память внутри), следующий вариант может быть более подходящим:

template<typename T> ref class GcAutoPtr sealed {
    T*  ptr;
    size_t  size;
public:
    GcAutoPtr(T*ptr,size_t size) : ptr(ptr), size(size) { 
        GC::AddMemoryPressure(size);
    }

    !GcAutoPtr() {
        GC::RemoveMemoryPressure(size);
        size=0;
        delete ptr;
        ptr = nullptr;
    }

    ~GcAutoPtr() { this->!GcAutoPtr();} //mostly just to avoid C4461

    T* get() {return ptr;}

    static T* operator->(GcAutoPtr<T>% gcPtr) { return gcPtr.ptr;}
    static operator T*(GcAutoPtr<T>% gcPtr) { return gcPtr.ptr; }
};
1 голос
/ 26 мая 2010

Вы не можете сохранить экземпляр в объекте управляемого класса и легко сгенерировать указатель на него.Это очень несовместимо с сборщиком мусора.Он будет перемещать управляемые объекты, когда сжимает кучу, что может произойти в непредсказуемые моменты.Попытка передать указатель на член userData приведет к ошибке компилятора.

Некоторые обходные пути: выделите экземпляр userData в куче с помощью new, сохраните указатель в управляемом объекте.Это, однако, довольно неэффективно, вам потребуется реализовать деструктор и финализатор для его освобождения.Делайте это только в том случае, если ожидается, что количество экземпляров управляемого класса ограничено.

Следующее решение - сгенерировать указатель во время вызова, используя pin_ptr <>.Это закрепляет управляемый объект в памяти, предотвращая его перемещение сборщиком мусора.Конечно, не очень эффективно.

Наконец, вы можете объявить экземпляр userData как локальную переменную в методе, который выполняет вызов, и скопировать в него экземпляр из управляемого объекта.Нет проблем с генерацией указателей на переменные стека, они не могут двигаться.Теперь вы также можете свободно объявлять структуру в своем управляемом классе в зависимости от того, что вам нужно.Предполагая, что эта структура не слишком велика, я бы выбрал ее.

0 голосов
/ 26 мая 2010

Сохранить указатель на данные в управляемом классе, удалить его в деструкторе.

ref class MyManagedClass
{
    userData *myUserData;

public:
    ~MyManagedClass()
    {
        if (myUserData)
            delete myUserData;
        myUserData = NULL;
    }

    short AddItem(long id, userData* data)
    {
        if (myUserData)
            delete myUserData;
        myUserData = new userData(*data);
    }
}
...