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()
た後、ネイティブ関数FeedDogNative
(上記のマーク(***)
)のどこかにあるときにGCによって一時停止された場合、C#MyFunc(ローカル)でも使用されなくなるため、マネージラッパーを収集できると見なされます。変数であり、FeedDogManaged
呼び出し後には使用されません)、どちらでもFeedDogManaged
。そして、これは実際に時々起こりました。GCはファイナライザーを呼び出します。ファイナライザーは、使用が終了していなくdelete
ても、ネイティブの犬のオブジェクトです。FeedDogNative
そのため、アンマネージコードは削除されたポインターを使用しています。
どうすればこれを防ぐことができますか?私はいくつかの方法を考えることができます(たとえばdog
、最後に使用するふりをするダミー呼び出しFeedDogManaged
)が、推奨される方法は何でしょうか?