delegates - c++/cli 终结器中免费 GCHandle 的最佳实践

标签 delegates garbage-collection c++-cli finalizer

我在 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/

相关文章:

c++-cli - 为什么不能将跟踪引用用作类成员?

iOS,在不使用 segue 的情况下为场景设置委托(delegate)

ios - ResearchKit 中的安全文本输入 ORKAnswerFormat

ios - Swift 中的相机和库操作

python - Python 的垃圾收集器会损害我的应用程序吗?

c# - 参数 DateTime ^A 的 C# 等效项是什么?

ios - 如何使用 Collection View 单元格转到下一个 View ?

cocoa - Core Foundation 对象的垃圾收集

java - 调整 G1GC 参数以进行积极的垃圾收集?

c# - 为什么 C# 不允许像 C++ 这样的非成员函数