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
;它取代了手动内存管理。)