C++/CLI:防止非托管资源的托管包装上的垃圾回收 我有一个C++非托管类 NATEVEDGO/,需要从C语言中使用,所以我创建了一个包装类:代码> MaultEdgEng/ // unmanaged C++ class class NativeDog { NativeDog(...); // constructor ~NativeDog(); // destructor ... } // C++/CLI wrapper class ref class ManagedDog { NativeDog* innerObject; // unmanaged, but private, won't be seen from C# ManagedDog(...) { innerObject = new NativeDog(...); ... } ~ManagedDog() // destructor (like Dispose() in C#) { // free unmanaged resources if (innerObject) delete innerObject; } !ManagedDog() // finalizer (like Finalize() in C#, in case { // the user forgets to dispose) ~ManagedDog(); // call destructor } }
一切都很好,我使用这样的类:C++/CLI:防止非托管资源的托管包装上的垃圾回收 我有一个C++非托管类 NATEVEDGO/,需要从C语言中使用,所以我创建了一个包装类:代码> MaultEdgEng/ // unmanaged C++ class class NativeDog { NativeDog(...); // constructor ~NativeDog(); // destructor ... } // C++/CLI wrapper class ref class ManagedDog { NativeDog* innerObject; // unmanaged, but private, won't be seen from C# ManagedDog(...) { innerObject = new NativeDog(...); ... } ~ManagedDog() // destructor (like Dispose() in C#) { // free unmanaged resources if (innerObject) delete innerObject; } !ManagedDog() // finalizer (like Finalize() in C#, in case { // the user forgets to dispose) ~ManagedDog(); // call destructor } },c#,garbage-collection,c++-cli,finalizer,C#,Garbage Collection,C++ Cli,Finalizer,一切都很好,我使用这样的类: // in C++/CLI // this function is called from C++ code void MyLibrary::FeedDogNative(NativeDog* nativedog) { ... // (***) } // this function is called from C#, passes on the dog to the native function void MyLibrary::FeedDogManaged
// in C++/CLI
// this function is called from C++ code
void MyLibrary::FeedDogNative(NativeDog* nativedog)
{
... // (***)
}
// this function is called from C#, passes on the dog to the native function
void MyLibrary::FeedDogManaged(ManagedDog^ dog)
{
NativeDog* rawdog = dog->innerObject;
MyLibrary::FeedDogNative(rawdog);
}
// C# client code
void MyFunc()
{
ManagedDog dog = new ManagedDog(...);
MyLibrary.FeedDogManaged(dog);
}
看看怎么了?起初我也没有,直到非常奇怪的事情开始不时发生。基本上,如果在调用MyFunc()
后,当程序位于本机函数feeddoginate
(上面标记为(***)
)的某个位置时,GC暂停了该程序,则它会认为可以收集托管包装,因为它将不再使用,也不会在C#MyFunc中使用(这是一个局部变量,在调用FeedDogManaged
后不会使用),都不是在FeedDogManaged
中。因此,这种情况实际上有时会发生。GC调用终结器,delete
s本机dog对象,即使FeedDogManaged
尚未使用完它!因此我的非托管代码现在使用的是删除指针
如何防止这种情况发生?我可以想出一些方法(例如,在
FeedDogManaged
末尾假装使用dog
),但建议的方法是什么?在托管代码中,在调用FeedDogManaged()之后添加GC.KeepAlive(dog)
:
您需要在您的
FeedDogManaged
函数中进行调用。这似乎是一个确切的用例。这就是我需要的,尽管正如max所说,最好将调用放在FeedDogManaged()中,因为它不是FeedDogManaged()的调用方的责任要处理这个问题。是的,完全同意。第一次读得不够仔细。我强烈建议使用cautonivativeptr()处理本机对象的生存期管理,然后让您的ref类
专注于向托管客户端公开功能。(这不会取代GC::KeepAlive
;它取代了手动内存管理。)