C ++ / cli Best practice for free GCHandle in finalizer

I have some functions in c and I would use this in a .net application. For this, I wrote a Wrapper class with C ++ / cli.

The c-interface has a callback function and is wrapped in a .net delegate.

But how can I free unmanaged resources for the gcHandle callback? Is IsAllocated and Free allowed from GCHandle in the finalizer? Because it is a managed ressource, and is it possible that gc has already released it?

Here is the code for the c interface:

// C functions #ifdef __cplusplus extern "C" { #endif typedef void (*my_native_callback)(const uint8_t buffer[], uint32_t buffer_len); void register_callback(my_native_callback c, uint32_t* id); void remove_callback(uint32_t id); #ifdef __cplusplus } #endif 

And here is the .net wrapper:

 // .net wrapper (c++/cli) public ref class MyWrapper { public: MyWrapper() { RegisterCallback(); } // Destructor. ~MyWrapper() { this->!MyWrapper(); } protected: // Finalizer. !MyWrapper() { RemoveCallback(); // <- Is this safe? // ... release other unmanaged ressorces } private: void RegisterCallback() { uint32_t id = 0; callbackDelegate_ = gcnew MyCallbackDelegate(this, &MyWrapper::OnCallback); callbackHandle_ = System::Runtime::InteropServices::GCHandle::Alloc(callbackDelegate_); System::IntPtr delegatePointer = System::Runtime::InteropServices::Marshal::GetFunctionPointerForDelegate(callbackDelegate_); register_callback(static_cast<my_native_callback>(delegatePointer.ToPointer()), &id); callbackId_ = id; } void RemoveCallback() { if (callbackId_) { remove_callback(callbackId_); callbackId_ = 0; } if (callbackHandle_.IsAllocated) // It this safe in the finalizer? { callbackHandle_.Free(); // It this safe in the finalizer? } callbackDelegate_ = nullptr; // It this safe in the finalizer? } void OnCallback(const uint8_t* buffer, uint32_t buffer_len) { // ... } private: [System::Runtime::InteropServices::UnmanagedFunctionPointer(System::Runtime::InteropServices::CallingConvention::Cdecl)] delegate void MyCallbackDelegate(const uint8_t* buffer, uint32_t buffer_len); MyCallbackDelegate^ callbackDelegate_; System::Runtime::InteropServices::GCHandle callbackHandle_; int callbackId_; // ... }; 

Is the code safe and what is the best fit for this?

Thanks in advance.

+4
source share
1 answer

There is no need to add a GCHandle sitelink to the delegate object. You already correctly store the link in the callbackDelegate_ field, enough to convince the garbage collector that the delegate is in use and should not be collected. No further help is required.

Just remove callbackHandle_ from your code.

+6
source

All Articles