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

时间:2013-03-11 13:17:07

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

我在c中有一些函数,我会在.net应用程序中使用它。 为此,我用C ++ / cli编写了一个Wrapper类。

在c接口中是一个回调函数,并将其包装在.net委托中。

但是我应该如何释放回调gcHandle的非托管资源? 是否允许在终结器中从GCHandle调用IsAllocated和Free? 因为它是一个托管资源,gc是否可以释放它?

以下是c接口的代码:

// 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_;
    // ... 
};

代码段是否安全,最佳做法是什么?

提前谢谢。

1 个答案:

答案 0 :(得分:6)

无需为委托对象添加额外的GCHandle引用。您已经在callbackDelegate_字段中正确存储了引用,足以说服垃圾收集器该委托正在使用中且不应该被收集。无需额外参考。

只需从代码中删除callbackHandle_即可。