托管类中的非托管结构实例

时间:2010-05-26 10:41:55

标签: visual-studio c++-cli managed-c++

我有一个相当具体的问题,我已经苦苦挣扎了几天。

我使用的是原生C ++,其中一种方法将ptr带到包含固定大小char数组的结构中。

e.g。

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

方法:

short AddItem(long id, userData* data);

我正在尝试从托管VC ++调用此函数,但我需要有一个userData实例,我可以在托管类中保留它。

任何人都可以帮忙解决这个问题吗?

由于

3 个答案:

答案 0 :(得分:3)

当首选带有垃圾收集的友好互操作时,我使用以下两个容器之一:

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 :(得分:1)

您无法将实例存储在托管类对象中并轻松生成指向它的指针。这与垃圾收集器非常不兼容。它会在压缩堆时移动托管对象,这可能在不可预测的时间发生。尝试将指针传递给userData成员将生成编译器错误。

一些解决方法:使用new在堆上分配userData实例,将指针存储在托管对象中。然而,这是非常低效的,你需要实现析构函数和终结器来释放它。仅当您希望托管类的实例数量有限时才执行此操作。

下一个解决方案是使用pin_ptr&lt;&gt;在调用时生成指针。它将托管对象固定在内存中,防止垃圾收集器移动它。当然不是非常有效。

最后,您可以将userData的实例声明为进行调用的方法中的局部变量,并将托管对象中的一个复制到其中。生成指向堆栈变量的指针没问题,它们无法移动。您现在也可以根据需要随意在托管类中声明结构。假设这个结构不是太大,那就是我要选择的。

答案 2 :(得分:0)

存储指向托管类中数据的指针,在析构函数中删除它。

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);
    }
}