Search code examples
c#lambdac++-clistd-function

Marshal::GetFunctionPointerForDelegate: should I release its result?


I'm converting a managed System.Action to an unmanaged std::function inside a C++/CLI project; should I release the given IntPtr after using the callback, or is it unnecessary?

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?
}

Solution

  • No. There is no Marshal class method to do this. Like all code that's dynamically generated, the thunk that's created by this method is associated with the AppDomain and gets unloaded when the AppDomain is unloaded.

    Note that this is not the case for the delegate object, it is subject to normal garbage collection rules. And you have to be careful, the thunk does not keep it alive. Which is a bug in your code, the delegate can be collected while the native code is busy executing. You'll need to add this line of code to the end of the method:

    GC::KeepAlive(callback);
    

    With the assumption that the callback will only be made as long as the Execute() method is executing. If the unmanaged code stores the function pointer beyond this method call then you have to store the delegate object somewhere to keep it valid. Use GCHandle.Alloc() to be absolutely sure (no need for pinning).