C++/CLI中std::function转托管委托失败,静态转换后委托为空
托管C++中正确绑定非托管
std::function回调的解决方案 问题根源
你的核心错误是混淆了非托管函数指针和std::function的本质:
Marshal::GetFunctionPointerForDelegate返回的是对应托管委托的非托管函数指针,仅匹配委托签名的原生函数指针,而非std::function指针。std::function是C++的 functor 包装对象,不能通过强制转换函数指针直接生成,这种非法转换会得到无效指针。
另外还有潜在问题:未处理非托管std::string与托管String^的类型转换,直接传递会导致内存错误或乱码。
正确实现方案
需要通过非托管适配器函数连接托管委托与非托管std::function,同时处理类型转换和GC引用保持:
1. 完整实现代码
#include <msclr/gcroot.h> #include <string> #include <functional> // 非托管代码(保持原逻辑不变) typedef std::function<void(const std::string &, float)> ProgressCallback; class MeshGenerator{ public: ProgressCallback progress; inline void SetCallback(ProgressCallback _callback){ this-> progress =_callback; } }; // 托管代码修改后 public delegate void CallbackDelegate(String^ cap, float data); public ref class MeshWrapper { private: MeshGenerator* gen; // 用gcroot持有托管委托,防止被GC回收 msclr::gcroot<CallbackDelegate^> _delegate; // 静态适配器函数,接收gcroot包装的托管实例 static void ProgressAdapter(const std::string& cap, float data, msclr::gcroot<MeshWrapper^> wrapperRoot) { // 转换非托管字符串到托管字符串 String^ managedCap = gcnew String(cap.c_str()); // 调用托管委托 wrapperRoot->_delegate->Invoke(managedCap, data); } public: inline MeshWrapper(){ this->gen = new MeshGenerator(); _delegate = gcnew CallbackDelegate(this, &MeshWrapper::Progress); // 用gcroot包装托管实例,避免GC回收 msclr::gcroot<MeshWrapper^> wrapperRoot = this; // 通过std::bind绑定适配器函数与上下文,生成合法的std::function ProgressCallback callback = std::bind(&MeshWrapper::ProgressAdapter, std::placeholders::_1, std::placeholders::_2, wrapperRoot); this->gen->SetCallback(callback); } inline void Progress(String^ cap, float s){ System::Console::WriteLine(cap + s.ToString()); } // 析构函数释放非托管资源 ~MeshWrapper(){ delete gen; gen = nullptr; } };
关键注意事项
- GC引用保持:必须用
msclr::gcroot持有托管委托和实例的引用,否则GC可能在回调触发前回收对象,导致程序崩溃。 - 类型转换:显式转换非托管
std::string到托管String^,避免内存访问错误。 std::function绑定:通过std::bind将适配器函数与托管上下文绑定,生成合法的std::function实例,而非直接转换函数指针。
单实例简化版本
如果仅需单个MeshWrapper实例,可简化实现:
public ref class MeshWrapper { private: MeshGenerator* gen; static msclr::gcroot<CallbackDelegate^> _staticDelegate; static void ProgressAdapter(const std::string& cap, float data) { String^ managedCap = gcnew String(cap.c_str()); _staticDelegate->Invoke(managedCap, data); } public: inline MeshWrapper(){ this->gen = new MeshGenerator(); _staticDelegate = gcnew CallbackDelegate(this, &MeshWrapper::Progress); ProgressCallback callback = &MeshWrapper::ProgressAdapter; this->gen->SetCallback(callback); } inline void Progress(String^ cap, float s){ System::Console::WriteLine(cap + s.ToString()); } ~MeshWrapper(){ delete gen; gen = nullptr; } };
注:此版本不支持多实例场景,静态委托会被所有实例共享。
内容的提问来源于stack exchange,提问作者The Overrider
相关产品推荐
相关产品推荐

