一部のC++/CLIコードでは、独自のマネージ.NETラッパーオブジェクトを作成するファクトリメソッドGetWrapper()
を持つネイティブクラスがあります。内部的には、GCHandleを介してラッパーへの弱い参照を保持します。 GetWrapper()
が呼び出されると、GCHandleがチェックされ、既存のラッパーへのハンドルが返されます(または、古いラッパーオブジェクトがガーベジコレクターによって破棄されたためにオブジェクトを指していない場合)。新しいものが作成されます返される。GCHandle.IsAllocatedは、弱いハンドルを破棄したオブジェクトに対してfalseを返しません。
// .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 tellsは、 "弱いハンドルを使用してGCHandleが利用可能かどうかを判断するときにこのプロパティを使用する"ように設定しました。しかし、それはいつも真実です。使用できない場合、ターゲットは代わりにnullptrです。
何かが見つからない、またはMSDNが間違っていますか?
コードに暗黙のスレッド競合があります。 IsAllocatedをテストした直後にGCが実行されることがあります。 –
@HansPassantはい、現在スレッドセーフではありません –