2010-05-26 156 views
1

我已经有了一个相当具体的问题,我一直在挣扎了几天。非托管结构实例在托管

我使用本地C++,所述方法之一需要一个PTR到含有固定大小字符数组的结构体。

例如

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

方法:

short AddItem(long id, userData* data); 

我想打电话从托管VC调用此++,但是我需要有用户数据的情况下,我可以在我的管理类继续保持的。

任何人都可以用如何实现这一目标帮助吗?

感谢

回答

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

前一种方法的优点是,即使你忘记处置的对象,内存压力,合理更新,垃圾收集发生在适当的频率:您可以按如下方式使用它。

如果你知道你roughtly分配数据元素的大小,但它不仅是直接的大小(即原生结构或类内部分配内存),下面的变体可能更合适:

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

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

一些解决方法:在新堆中分配的用户数据情况下,指针存储在管理对象。然而,这是非常低效的,你需要实现一个析构函数和一个终结器来释放它。只有在您期望受管理类的实例数量有限时才这样做。

接下来的解决方案是在产生呼叫的时间指针,使用pin_ptr <>。将管理对象固定在内存中,防止垃圾收集器移动它。当然不是非常有效。

最后,你可以声明用户数据的实例作为使呼叫的方法的局部变量和复制管理对象的一成多吧。生成指向堆栈变量的指针没有问题,它们不能移动。您现在可以自由地以您想要的方式在您的托管班级中声明结构。假设这个结构不是太大,那就是我会选择的。