You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

将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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.06 10:44:52