8

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?
}
Notoriousxl
  • 1,540
  • 1
  • 16
  • 27

3 Answers3

9

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.

Hans Passant
  • 922,412
  • 146
  • 1,693
  • 2,536
4

No, but if you called Alloc to create a GCHandle on the callback delegate, you have to free that handle with GCHandle.Free(). Here is a good article including how to prevent the GC from prematurely disposing your delegate: http://msdn.microsoft.com/en-us/library/367eeye0%28v=VS.100%29.aspx

edtheprogrammerguy
  • 5,957
  • 6
  • 28
  • 47
2

You will not need to release the pointer. You already have your pointer to the function (that is a 32/64 bit size depending on your machine architecture). If the .net framework infrastructure needed something more to run the pointer it would be the same for all methods so it would be statically allocated (no state).

nemenos
  • 877
  • 1
  • 10
  • 23
  • I don't think this is true. For instance, GetFunctionPointerForDelegate can return different values for the same lambda, since the lambda can capture data and that data can be different for different instances, even thought the code of the lambda is constant. I was surprised by this, but it is very convenient when interfacing with C-code - my callback can access captured data. – avl_sweden Jun 10 '20 at 06:34
  • @avl_sweden: You can have different delegate instances from the same lambda, but the state is fully encoded in the delegate instance; it is sufficient to have only one function pointer per delegate instance. – Ben Voigt May 12 '21 at 21:06
  • Aha, so is each closure invocation its own delegate instance? – avl_sweden May 14 '21 at 06:30