在某些C ++ / CLI代码中,我有一个本机类,它有一个工厂方法GetWrapper()
,用于创建自己的托管.NET包装器对象。在内部,它通过GCHandle对其包装器进行弱引用。调用GetWrapper()
时,将检查GCHandle并返回现有包装器的句柄,或者(如果它不再指向对象,因为旧的包装器对象已被垃圾收集器销毁)a新的一个被创建一个返回。
// .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 to“在使用弱句柄时使用此属性来确定GCHandle是否仍然可用。”但它总是如此。如果它不可用,则目标是nullptr。
我错过了什么或者MSDN错了吗?
答案 0 :(得分:2)
我对MSDN doco的读取是m_wrapprGCHandle.IsAllocated
将返回true,直到调用m_wrapperGCHandle.Free
- IsAllocated
属性检查句柄的状态而不是引用的状态由把手握住。
如您所知,当对象被垃圾回收时,m_wrapperGCHandle.Target
为空。我使用了与示例代码中的类似方法来生成托管包装类,并且我总是检查Target
是否为null,并在Target
为空时重新生成包装器对象。
另外,一个建议......它看起来好像你的代码中有句柄泄漏,因为你在没有相应GCHandle::Alloc
调用的情况下调用m_wrapperGCHandle.Free
。尝试在类构造函数中调用Alloc
,并在析构函数中调用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
链。