2010-12-06 17 views
12

私は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を使用している疑似呼び出し)が、推奨される方法は何ですか?マネージコードで

+0

ネイティブオブジェクトのライフタイム管理を処理するためにCAutoNativePtr(http://www.codeproject.com/KB/mcpp/CAutoNativePtr.aspx)を使用することを強くお勧めします。その後、管理対象クライアントに機能を公開するための 'ref class' 。 (これは 'GC :: KeepAlive'を置き換えるものではなく、手動メモリ管理を置き換えます)。 –

答えて

7

あなたのFeedDogManaged機能でGC::KeepAlive()呼び出しを必要としています。そのための正確な使用例のようです。

+0

パーフェクト、ありがとう! – Laurent

4

、FeedDogManaged(への呼び出し、次のGC.KeepAlive(dog)を追加):

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

+0

これは私が必要とするものですが、maxと言っても_inside_ FeedDogManaged()は呼び出し元の責任ではないのでこれを処理するFeedDogManaged()。 – Laurent

+0

うん、完全に同意する。初めて慎重に読んだことはありませんでした。 – twon33

関連する問題