我有一个相当具体的问题,我已经苦苦挣扎了几天。
我使用的是原生C ++,其中一种方法将ptr带到包含固定大小char数组的结构中。
e.g。
struct userData {
char data1[10];
char data2[10];
};
方法:
short AddItem(long id, userData* data);
我正在尝试从托管VC ++调用此函数,但我需要有一个userData实例,我可以在托管类中保留它。
任何人都可以帮忙解决这个问题吗?
由于
答案 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);
}
}