私はC#からアンマネージドクラスNativeDog
を使用する必要があるので、ラッパークラスManagedDog
を作成しました。C++/CLI:管理されていないリソースのマネージラッパーでガベージコレクションを防止する
// 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は、FeedDogNative
がそれを使用し終えていなくても、delete
がネイティブの犬オブジェクトであるファイナライザを呼び出します。だから私のアンマネージドコードは今、削除されたポインタを使用しています。
どうすればこの問題を防ぐことができますか?私はいくつかの方法を考えることができます(例えば、FeedDogManaged
の末尾にdog
を使用している疑似呼び出し)が、推奨される方法は何ですか?マネージコードで
ネイティブオブジェクトのライフタイム管理を処理するためにCAutoNativePtr(http://www.codeproject.com/KB/mcpp/CAutoNativePtr.aspx)を使用することを強くお勧めします。その後、管理対象クライアントに機能を公開するための 'ref class' 。 (これは 'GC :: KeepAlive'を置き換えるものではなく、手動メモリ管理を置き換えます)。 –