0

GetWrapper()一部のC++/ CLIコードには、独自のマネージド.NETラッパーオブジェクトを作成するためのファクトリメソッドを持つネイティブクラスがあります。内部的には、GCHandleを介したラッパーへの弱参照を保持しています。がGetWrapper()呼び出されると、GCHandleがチェックされ、既存のラッパーへのハンドルが返されるか、(古いラッパーオブジェクトがガベージコレクターによって破棄されたためにオブジェクトを指していない場合)、新しいラッパーが作成されます。戻ってきた。

// .h
class NativeClass
{
public:
    WrapperClass^ GetWrapper();
private:
    WrapperClass^ GetNewWrapper();
    GCHandle m_wrapperGCHandle;
};

// .cpp
WrapperClass^ NativeClass::GetWrapper()
{
    if(m_wrapperGCHandle.IsAllocated)
    {
        try
        {
            WrapperClass^ wrapper = nullptr;
            wrapper = dynamic_cast<WrapperClass^>(wrapperGCHandle.Target);

            if(wrapper == nullptr)
            {
                return GetNewWrapper();
            }
            else
            {
                return wrapper;
            }
         }
         catch(System::InvalidOperationException^)
         {
             return GetNewWrapper();
         }
    else
    {
        return GetNewWrapper();
    }
}

WrapperClass^ NativeClass::GetNewWrapper()
{
    WrapperClass^ wrapper = gcnew WrapperClass(/*some args*/);
    m_wrapperGCHandle = GCHandle::Alloc(wrapper, GCHandleType::Weak);
}

奇妙なことに、ラッパーがガベージコレクションされた場合でも、m_wrapperGCHandle.IsAllocated 常にtrueが返されます。MSDN、「弱いハンドルを使用してGCHandleがまだ使用可能かどうかを判断するときに、このプロパティを使用する」と指示しています。しかし、それは常に真実です。使用できない場合、ターゲットは代わりにnullptrです。

何かが足りないのですか、それともMSDNが間違っていますか?

4

1 に答える 1

2

私がMSDNDocoを読んだところ、が呼び出されるm_wrapprGCHandle.IsAllocatedまでtrueが返されます。プロパティは、ハンドルが保持している参照の状態ではなく、ハンドルの状態をチェックしています。m_wrapperGCHandle.FreeIsAllocated

お気づきのとおりm_wrapperGCHandle.Target、オブジェクトがガベージコレクションされている場合はnullです。サンプルコードにあるものと同様のメソッドを使用して、マネージラッパークラスを生成しました。常にnullかどうかを確認し、Targetnullの場合はラッパーオブジェクトを再生成しTargetます。

GCHandle::Allocまた、提案...対応する呼び出しなしで呼び出しているため、コードにハンドルリークがあるように見えますm_wrapperGCHandle.FreeAlloctoの呼び出しをクラスコンストラクタに入れ、toの呼び出しをFreeデストラクタに入れてみてください。

NativeClass::NativeClass()
{
    m_wrapperGCHandle = GCHandle::Alloc(nullptr, GCHandleType::Weak);
}

NativeClass::~NativeClass()
{
    m_wrapperGCHandle.Free();
}

その場合、あなたのGetNewWrapper方法は単純です:

WrapperClass^ NativeClass::GetNewWrapper()
{
    m_wrapperGCHandle.Target = gcnew WrapperClass(/*some args*/);
}

if(m_wrapperGCHandle.IsAllocated) - elseメソッドからチェーンを削除できますGetWrapper

于 2012-05-11T13:43:07.570 に答える