我有一个需要在C#中使用的C ++非托管类NativeDog
,所以我创建了一个包装类ManagedDog
。
// 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
}
}
一切都很好,我使用这样的课程:
// 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()
之后,当GC在本机函数FeedDogNative
(上面标记为(***)
)中的某个位置暂停程序时,它会认为可以收集托管包装器,因为它将不再使用C#MyFunc(它是一个局部变量,不会在FeedDogManaged
调用后使用),也不会在FeedDogManaged
中使用。所以这实际上偶尔会发生。 GC调用Finalizer,delete
是本地狗对象,即使FeedDogNative
尚未使用它!所以我的非托管代码现在使用删除的指针。
我该怎样防止这种情况?我可以想到一些方法(例如假装在dog
结束时假装使用FeedDogManaged
),但推荐的方式是什么?
答案 0 :(得分:7)
您的FeedDogManaged
功能需要GC::KeepAlive()
来电。这似乎是一个确切的用例。
答案 1 :(得分:4)
在托管代码中,在调用FeedDogManaged()之后添加GC.KeepAlive(dog)
:
http://msdn.microsoft.com/en-us/library/system.gc.keepalive(VS.71).aspx