我在 c 中有一些函数,我会在 .net 应用程序中使用它。 为此,我用 C++/cli 编写了一个包装器类。
C 接口(interface)中有一个回调函数,并将其包装在 .net 委托(delegate)中。
但是我应该如何释放回调gcHandle的非托管资源呢? 是否允许在终结器中从 GCHandle 调用 IsAllocation 和 Free? 因为它是托管资源,gc 是否可能已经释放它?
这是 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
这是 .net 包装器:
// .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_;
// ...
};
代码片段安全吗?最佳实践是什么?
提前谢谢您。
最佳答案
无需向委托(delegate)对象添加额外的 GCHandle 引用。您已经在callbackDelegate_字段中正确存储了一个引用,足以让垃圾收集器相信委托(delegate)正在使用中并且不应被收集。不需要额外的引用。
只需从代码中删除callbackHandle_即可。
关于delegates - c++/cli 终结器中免费 GCHandle 的最佳实践,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15339608/