2010-05-26 158 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 <>。將管理對象固定在內存中,防止垃圾收集器移動它。當然不是非常有效。

最後,你可以聲明用戶數據的實例作爲使呼叫的方法的局部變量和複製管理對象的一成多吧。生成指向堆棧變量的指針沒有問題,它們不能移動。您現在可以自由地以您想要的方式在您的託管班級中聲明結構。假設這個結構不是太大,那就是我會選擇的。