Visual c++ 以非托管对象作为托管代码的参数高效调用非托管方法
我有下面的场景。托管代码将初始化类的大量对象,该类是非托管结构的包装器。有两种方法我可以做到这一点。一种是有一个托管类包装器,它只有一个指向非托管对象的指针。另一种方法是拥有一个完整的托管类,并在需要调用非托管方法时创建非托管对象。我提供了以下两种方法。有人告诉我,如果我使用方法1(有一个指向非托管对象的指针),GC在了解非托管部分时会有很多问题,最好使用方法2。有没有人告诉我哪个更好,或者是否有其他更好的方法。我对方法2的担忧是,每次调用非托管方法时都会有来回的复制。我不确定GC问题是否超过了它 编辑-第一种方法有一个ref类,第二种方法有一个value类。第二个是值的原因是它可以更有效地添加到列表中 在非托管状态下:Visual c++ 以非托管对象作为托管代码的参数高效调用非托管方法,visual-c++,c++-cli,Visual C++,C++ Cli,我有下面的场景。托管代码将初始化类的大量对象,该类是非托管结构的包装器。有两种方法我可以做到这一点。一种是有一个托管类包装器,它只有一个指向非托管对象的指针。另一种方法是拥有一个完整的托管类,并在需要调用非托管方法时创建非托管对象。我提供了以下两种方法。有人告诉我,如果我使用方法1(有一个指向非托管对象的指针),GC在了解非托管部分时会有很多问题,最好使用方法2。有没有人告诉我哪个更好,或者是否有其他更好的方法。我对方法2的担忧是,每次调用非托管方法时都会有来回的复制。我不确定GC问题是否超过了
struct A_UNMANAGED
{
int a;
int b[20];
};
void GetData(A_UNMANAGED& a); // populates A
在管理模式下(第一种方法)
public ref class A\u管理
{
A_无管理*ap;
公众:
物业系统::UInt32 a
{
System::UInt32 get(){return ap->a;}
无效集(系统::UInt32值){ap->a=value;}
}
属性数组^b
{
数组^get(){return ap->b;}
void set(数组^value){b=value;}//假定此副本有效
}
内部:
void GetData()
{
获取数据(ap);
}
};
在托管(第二种方法)中(编辑:更新为ref。假设所有垃圾收集和指针创建都正确写入)
A类公共价值管理
{
系统:UInt32 a;
数组^b;
公众:
物业系统::UInt32 a
{
System::UInt32 get(){返回一个;}
无效集(系统::UInt32值){a=value;}
}
属性数组^b
{
数组^get(){return b;}
无效集(数组^value){b=value;}
}
内部:
void GetUnmanaged(A_UNMANAGED&obj1)
{
obj1.a=a;
pin_ptr bp=&b[0];
memcpy(obj1.b,bp,20);
}
void GetData()
{
A_非托管obj2;
GetUnmanaged(obj2);
GetData(obj2);
//从obj2复制到成员变量
}
};
不,第一个代码片段是以规范的方式进行的。垃圾收集器只移动指针,不移动指向的对象。如果该运算符应该已分配malloc()或新运算符,则无法移动该运算符
在代码中还有几个严重的问题。除非GetData()通过引用获取其参数,否则您似乎不会为非托管的_分配内存。从未调用GetData()。这通常必须是一个ref类(而不是ref值),因此可以提供析构函数和终结器来释放内存。b
属性设置程序将使用StackOverflowException轰炸您的程序。在处理这个项目之前,一定要学习语言
检查示例代码。正如Hans所说,第一种方法是通常的方法(尽管我个人认为,在这种特殊情况下,p/Invoke会更简洁…)。但是,您的
A_MANAGED::b
实现将无法工作,如果您尝试简单地编译它,这是显而易见的。请尝试以下方法:
public ref class A_MANAGED
{
A_UNMANAGED* ap;
public:
A_MANAGED() : ap(new A_UNMANAGED() ) { }
~A_MANAGED() { this->!A_MANAGED(); }
!A_MANAGED() { delete ap; ap = nullptr; }
property int a
{
int get() { return ap->a; }
void set(int value) { ap->a = value; }
}
property array<int>^ b
{
array<int>^ get()
{
using System::Runtime::InteropServices::Marshal;
array<int>^ arr = gcnew array<int>(20);
Marshal::Copy(System::IntPtr(ap->b), arr, 0, 20);
return arr;
}
void set(array<int>^ value)
{
using System::Runtime::InteropServices::Marshal;
Marshal::Copy(value, 0, System::IntPtr(ap->b), 20);
}
}
internal:
void GetData()
{
::GetData(*ap);
}
};
public ref class A\u管理
{
A_非托管*应付账款;
公众:
A_托管():ap(新A_非托管()){}
~A_MANAGED(){这个->!A_MANAGED();}
!A_MANAGED(){delete ap;ap=nullptr;}
属性int a
{
int get(){return ap->a;}
无效集(int值){ap->a=value;}
}
属性数组^b
{
数组^get()
{
使用System::Runtime::InteropServices::封送;
数组^arr=gc新数组(20);
封送:复制(系统::IntPtr(ap->b),arr,0,20);
返回arr;
}
无效集(数组^value)
{
使用System::Runtime::InteropServices::封送;
封送:复制(值,0,系统::IntPtr(ap->b),20);
}
}
内部:
void GetData()
{
::GetData(*ap);
}
};
还有一个关于从属性返回数组的常见警告:这是一个坏主意。除非您真的想与非托管类的公共接口保持奇偶性,
b
实际上应该是一对set/get函数,而不是一个属性。我想标记第一个类引用。我有析构函数和终结器,但没有在这里编写它们。同样,正如我所指定的,假设b副本有效。我的问题是要知道哪种方法更好,如果GC和值问题是真的,那么你通过发布蹩脚的代码浪费了我的时间。这样做的目的是什么?否则它不会改变我的答案。
public value class A_MANAGED
{
System::UInt32 a;
array<System::UInt32>^ b;
public:
property System::UInt32 a
{
System::UInt32 get() { return a; }
void set(System::UInt32 value) { a = value; }
}
property array<System::UInt32>^ b
{
array<System::UInt32>^ get() { return b; }
void set(array<System::UInt32>^ value) { b = value; }
}
internal:
void GetUnmanaged(A_UNMANAGED& obj1)
{
obj1.a = a;
pin_ptr<System::UInt32> bp = &b[0];
memcpy(obj1.b, bp, 20);
}
void GetData()
{
A_UNMANAGED obj2;
GetUnmanaged(obj2);
GetData(obj2);
// copy from obj2 to member variables
}
};
public ref class A_MANAGED
{
A_UNMANAGED* ap;
public:
A_MANAGED() : ap(new A_UNMANAGED() ) { }
~A_MANAGED() { this->!A_MANAGED(); }
!A_MANAGED() { delete ap; ap = nullptr; }
property int a
{
int get() { return ap->a; }
void set(int value) { ap->a = value; }
}
property array<int>^ b
{
array<int>^ get()
{
using System::Runtime::InteropServices::Marshal;
array<int>^ arr = gcnew array<int>(20);
Marshal::Copy(System::IntPtr(ap->b), arr, 0, 20);
return arr;
}
void set(array<int>^ value)
{
using System::Runtime::InteropServices::Marshal;
Marshal::Copy(value, 0, System::IntPtr(ap->b), 20);
}
}
internal:
void GetData()
{
::GetData(*ap);
}
};