11

我有一个NativeDog需要从 C# 使用的 C++ 非托管类,所以我创建了一个包装类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是本机 dog 对象,即使FeedDogNative它还没有使用完!所以我的非托管代码现在正在使用已删除的指针。

我怎样才能防止这种情况?我可以想到一些方法(例如,假装dog在末尾使用的虚拟调用FeedDogManaged)但是推荐的方法是什么?

4

2 回答 2

7

你需要GC::KeepAlive()在你的FeedDogManaged函数中调用。似乎这是一个确切的用例。

于 2010-12-06T13:40:13.440 回答
4

在您的托管代码中,添加GC.KeepAlive(dog)以下对 FeedDogManaged() 的调用:

http://msdn.microsoft.com/en-us/library/system.gc.keepalive(VS.71).aspx

于 2010-12-06T13:39:44.953 回答