将C++类转为C#托管类遇构造函数及容器转换问题求助
问题解决:C++类转C#托管结构体时的构造调用失败与STL类型转换问题
尝试将C++的
memoryTest类转换为C#托管结构体__CClass,调用构造函数时抛出System.Runtime.InteropServices.MarshalDirectiveException,提示“Cannot marshal 'parameter #1': Pointers cannot reference marshaled structures. Use ByRef instead.”,同时不清楚如何转换std::shared_ptr和std::deque<std::vector<int>>类型。
原代码
C++类代码
class memoryTest { public: std::shared_ptr<void> object_ptr; std::deque<std::vector<int>> prev_vec_deque; std::string _cfg, _weight; int cur_id; float nms; bool wait_stream; };
C#托管结构体代码
public unsafe struct __CClass { //IntPtr* _vtable; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x2)] IntPtr[] shared_ptr_0; [MarshalAs(UnmanagedType.Struct, SizeConst = 0x5)] List<bbox_t[]> tracking_id; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 0x28)] public byte[] portText1; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 0x28)] public byte[] portText2; int cur_id; float nms; bool wait_stream; };
调用代码
_cpp = (__CClass*)Marshal.AllocHGlobal((IntPtr)(sizeof(__CClass))); RtlZeroMemory((IntPtr)_cpp, (UIntPtr)sizeof(__CClass)); // 调用构造函数 _CClass_Constructor(_cpp, configurationFilename, weightsFilename, 0, 1);
问题解决
1. 修复MarshalDirectiveException异常
异常原因是直接传递结构体指针给非托管函数,CLR无法直接封送指向托管结构体的指针。解决方式:
- 放弃强制转换为
__CClass*,直接使用IntPtr传递分配好的非托管内存地址。 - 修正后的调用代码:
IntPtr cppInstance = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(__CClass))); RtlZeroMemory(cppInstance, (UIntPtr)Marshal.SizeOf(typeof(__CClass))); // 构造函数声明中第一个参数类型设为IntPtr,直接传cppInstance _CClass_Constructor(cppInstance, configurationFilename, weightsFilename, 0, 1);
2. 处理std::shared_ptr的转换
std::shared_ptr是C++智能指针,内部结构依赖编译器实现,不能直接用固定大小数组模拟:
- 在C#结构体中将其视为不透明指针,用
IntPtr表示:
IntPtr object_ptr;
- 如需操作该指针,必须在C++层封装导出函数(如获取对象、释放资源等),C#通过这些函数间接操作,不直接触碰内部结构。
3. 处理std::deque<std::vector>的转换
std::deque和std::vector是动态容器,内存布局与C#的List完全不兼容:
- 在C#结构体中用
IntPtr作为容器的不透明引用:
IntPtr prev_vec_deque;
- 在C++层编写导出函数(如
GetDequeSize、GetVectorAt、AddVectorToDeque),供C#调用以实现对容器的操作。
4. 修正std::string的映射
std::string是动态字符串,不能用固定大小字节数组映射:
- 在C#结构体中用
IntPtr表示:
IntPtr _cfg; IntPtr _weight;
- 通过C++导出函数将字符串内容复制到C#缓冲区,或者返回
const char*供C#用Marshal.PtrToStringAnsi转换。
修正后的C#结构体示例
public struct __CClass { IntPtr object_ptr; IntPtr prev_vec_deque; IntPtr _cfg; IntPtr _weight; int cur_id; float nms; bool wait_stream; };
内容的提问来源于stack exchange,提问作者flydream
相关产品推荐
相关产品推荐

