Marshal::GetFunctionPointerForDelegate:我需要释放它的结果吗?

8

我在一个C++/CLI项目中将托管的System.Action转换为非托管的std::function;在使用回调后,我需要释放给定的IntPtr吗,或者这是不必要的?

void MyClass::Execute(System::Action^ callback)
{           

    IntPtr callbackPtr = Marshal::GetFunctionPointerForDelegate(callback);
    std::function<void (void)> nativeCallback = static_cast<void (__stdcall *) (void)>(callbackPtr.ToPointer());

    m_nativeObject->Execute(wrappedCallback);

    // should I release callbackPtr here?
}
3个回答

9

没有Marshal类方法可以做到这一点。像所有动态生成的代码一样,由该方法创建的thunk与AppDomain关联,并在卸载AppDomain时卸载。

请注意,对于委托对象,情况并非如此,它受到正常垃圾回收规则的约束。而且你必须小心,thunk不会使其保持活动状态。这是你代码中的一个错误,委托可以在本机代码正在忙于执行时被收集。你需要在方法末尾添加这行代码:

GC::KeepAlive(callback);

假设回调函数只在执行Execute()方法时被调用。如果非托管代码将函数指针存储在此方法调用之外,则必须将委托对象存储在某个位置以保持其有效性。


即使 m_nativeObject->Execute(wrappedCallback) 是同步的,也是吗? - Notoriousxl
这是我第一次看到GC.KeepAlive有任何用处。 - TakeMeAsAGuest

4

2

您不需要释放指针。 您已经拥有函数的指针(这是一个32/64位大小,取决于您的机器架构)。如果 .net 框架基础设施需要运行指针所需的更多内容,则所有方法都相同,因此它将被静态分配(没有状态)。


我不认为这是正确的。例如,GetFunctionPointerForDelegate可以为相同的lambda返回不同的值,因为lambda可以捕获数据,并且该数据对于不同的实例可能是不同的,即使lambda的代码是恒定的。我对此感到惊讶,但在与C代码进行交互时非常方便 - 我的回调可以访问已捕获的数据。 - avl_sweden
@avl_sweden:您可以从同一个lambda表达式中获得不同的委托实例,但状态完全编码在委托实例中;每个委托实例只需要一个函数指针即可。 - Ben Voigt
啊哈,所以每个闭包调用都是它自己的委托实例? - avl_sweden

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接