如何解决当托管句柄保存在托管容器IList <Foo ^>中时,是否有必要在C ++ / CLI中使用GC :: KeepAlive?
| 我对于何时需要在C ++ / CLI包装器代码中使用KeepAlive以及如何处理生存期感到困惑。请考虑以下代码,并记下我询问是否需要KeepAlive的地方。// convert from managed to native string
inline std::string ToStdString(String^ source)
{
if (String::IsNullOrEmpty(source))
return std::string();
int len = ((source->Length+1) * 2);
/*** Do I need GC::KeepAlive(source) here? ***/
char *ch = new char[ len ];
bool result ;
{
pin_ptr<const wchar_t> wch = PtrToStringChars( source );
result = wcstombs( ch,wch,len ) != -1;
}
std::string target = ch;
delete ch;
if(!result)
throw gcnew Exception(\"error converting System::String to std::string\");
return target;
}
// convert from native to managed string
inline String^ ToSystemString(const std::string& source)
{
return gcnew String(source.c_str());
}
// unmanaged C++ class
struct NativeDog
{
std::string name;
std::string bark() const {return \"woof\";}
void eat(std::string& food) const {food.clear();}
};
typedef shared_ptr<NativeDog> NativeDogPtr;
// C++/CLI wrapper class
ref class ManagedDog
{
NativeDogPtr* base_;
NativeDog& base() {return **base_;}
ManagedDog() {base_ = new NativeDogPtr(new NativeDog);}
~ManagedDog() {if (base_) delete base_;}
!ManagedDog() {delete this;}
property String^ name
{
String^ get() {return ToSystemString(base().name);}
void set(String^ name)
{
base().name = ToStdString(name);
/*** Do I need GC::KeepAlive(name) here? ***/
}
}
String^ bark() {return ToSystemString(base().bark());}
void eat(String^ food)
{
std::string nativeFood = ToStdString(food);
base().eat(nativeFood);
food = ToSystemString(nativeFood);
/*** Do I need GC::KeepAlive(food) here? ***/
}
};
// unmanaged C++ class
struct NativeKennel
{
vector<NativeDogPtr> dogs;
};
// C++/CLI wrapper class
ref class ManagedKennel
{
NativeKennel* base_;
NativeKennel& base() {return *base_;}
IList<ManagedDog^>^ dogs;
void addDog(ManagedDog^ dog)
{
base().dogs.push_back(*dog->base_);
dogs->Add(dog);
/*** Do I need GC::KeepAlive(dog) here? Will the IList manage the ManagedDog lifetimes? ***/
}
};
解决方法
恰好在调用托管委托的函数指针之前。
这是一种常见的故障模式,垃圾收集器无法看到本机代码保存的任何引用。托管代码必须存储对委托本身的引用,以防止其被垃圾收集。有一个调试器助手,不知道为什么看不到它。此MSDN库文章中的更多详细信息。
,以上都不是!
如果您使用C ++ / CLI访问托管类,则KeepAlive将无济于事。您需要将数据固定在内存中,以防止垃圾回收后重新定位数据。在所有这些示例中,这都是通过调用的函数隐式完成的。
KeepAlive的目标不同。上次取消引用对象后,将立即对堆栈中存储的引用进行垃圾回收。 KeepAlive通过将对象的生存期延长到KeepAlive调用之后,来防止这种情况的发生。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。