C++ cli GCHandle.IsAllocated不会为已销毁对象的弱句柄返回false
在一些C++/CLI代码中,我有一个本机类,它有一个工厂方法C++ cli GCHandle.IsAllocated不会为已销毁对象的弱句柄返回false,c++-cli,C++ Cli,在一些C++/CLI代码中,我有一个本机类,它有一个工厂方法GetWrapper(),用于创建自己的托管.NET包装对象。在内部,它通过GCHandle持有对其包装器的弱引用。调用GetWrapper()时,将检查GCHandle并返回现有包装的句柄,或者(如果它不再指向对象,因为旧包装对象已被垃圾收集器销毁)创建一个新的包装并返回 // .h class NativeClass { public: WrapperClass^ GetWrapper(); private: Wra
GetWrapper()
,用于创建自己的托管.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);
}
/.h
类本地类
{
公众:
包装器类^GetWrapper();
私人:
WrapperClass ^GetNewWrapper();
GCHandle m_包装器GCHandle;
};
//.cpp
包装器类^NativeClass::GetWrapper()
{
if(m_wrapperGCHandle.IsAllocated)
{
尝试
{
WrapperClass^ wrapper=nullptr;
wrapper=dynamic_cast(wrapperGCHandle.Target);
if(wrapper==nullptr)
{
返回GetNewWrapper();
}
其他的
{
返回包装器;
}
}
捕获(系统::InvalidOperationException^)
{
返回GetNewWrapper();
}
其他的
{
返回GetNewWrapper();
}
}
WrapperClass^NativeClass::GetNewWrapper()
{
WrapperClass^wrapper=gcnew WrapperClass(/*一些参数*/);
m_wrapperGCHandle=GCHandle::Alloc(wrapper,GCHandleType::弱);
}
现在奇怪的是,m_wrapperGCHandle.IsAllocated
始终返回true,即使包装已被垃圾收集。MSDN允许“在使用弱句柄时使用此属性来确定GCHandle是否仍然可用。”。但这总是正确的。如果不可用,则目标为空PTR
我是否遗漏了什么或MSDN有错?我对MSDN文档的理解是
m_wrapprgHandle.IsAllocated
将返回true,直到调用m_wrappergHandle.Free
-IsAllocated属性检查句柄的状态,而不是句柄所持有的引用的状态
正如您所注意到的,m_wrapperGCHandle.Target
在垃圾收集对象时为null。我使用了与示例代码中类似的方法来生成托管包装类,我总是检查Target
是否为null,如果Target
为null,则重新生成包装对象
另外,还有一个建议……在我看来,您的代码中似乎存在句柄泄漏,因为您在调用GCHandle::Alloc
时没有相应的m包装器GCHandle.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*/);
}
您可以从
GetWrapper
方法中删除if(m_wrapperGCHandle.IsAllocated)-else
链。代码中存在隐式线程竞争。GC可能在您测试IsAllocated后立即运行。@HansPassant是的,它当前不是线程安全的