11

NativeDogC#から使用する必要のある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()た後、ネイティブ関数FeedDogNative(上記のマーク(***))のどこかにあるときにGCによって一時停止された場合、C#MyFunc(ローカル)でも使用されなくなるため、マネージラッパーを収集できると見なされます。変数であり、FeedDogManaged呼び出し後には使用されません)、どちらでもFeedDogManaged。そして、これは実際に時々起こりました。GCはファイナライザーを呼び出します。ファイナライザーは、使用が終了していなくdeleteても、ネイティブの犬のオブジェクトです。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 に答える