3

VS2008で次のC++/CLIコードをビルドすると、CA1001のコード分析に関する警告が表示されます。GCが自動的にクラスのメンバーを処分しないのはなぜですか?

ref class A 
{ 
public: 
    A() { m_hwnd = new HWND; } 
    ~A() { this->!A(); } 
protected: 
    !A() { delete m_hwnd; } 
    HWND* m_hwnd; 
}; 

ref class B 
{ 
public: 
    B() { m_a = gcnew A(); } 
protected: 
    A^ m_a; 
}; 

警告:CA1001:Microsoft.Design: 'A': が、それは次のよう IDisposableインター種類のメンバーが作成されます ので、 'B' にIDisposableを実装します。

この警告を解決するには、私は、クラスBにこのコードを追加する必要があります:

~B() { delete m_a; } 

しかし、私はなぜ理解していません。クラスAは、デストラクタ(およびファイナライザ)を介してIDisposableを実装します。
確実にAがガベージコレクションされると、Aのファイナライザまたはデストラクタが呼び出され、アンマネージリソースが解放されます。

なぜAメンバーの「削除」を呼び出すためにBがデストラクタを追加する必要がありますか?
Bが明示的に "delete m_a"を呼び出す場合、GCはAのデストラクタを呼び出しますか?


編集

ref class B 
{ 
public: 
    B() { } 
protected: 
    A  m_a; 
}; 

が、これは常に可能ではない:あなたがこのように、メンバーを宣言する「シンタックスシュガー」メソッドを使用している場合、これは自動的に動作ようです。

なぜ、他の誰もそれにポインタを持っていなければ、A ^のマネージリファレンスポインタを自動的に破棄するのにGCが巧妙ではないのですか?

答えて

2

メンバーにスタックセマンティクスを使用し、そのクラスにデストラクタを追加する必要があります。 その後、メンバーは処分されます。 メンバーがまだ参照されhttp://msdn.microsoft.com/en-us/library/ms177197.aspx

ref class B 
{ 
public: 
    B() {} 
    ~B() {} 
protected: 
    A m_a; 
}; 

を参照してください。まだヒープ上に作成されています。

編集:.NETで

処分は、最高の状態で不幸であるC#で全体の決定論的挙動が壊れていると、あなたは処分で本当にrigerousする必要がほとんどのC++開発者が期待する動作を取得するために呼び出します。

C++/cliのスタックセマンティクスでは、それを改善します。あなたがそれらを使用できないなら、あなたは明示的にdisposeを呼び出す必要があります。これは、C++/cliの中でdestructorによって表されています。

メンバにコールを自動的に連鎖させる唯一の方法は、メンバがC#のように通常の管理ポインタであれば、スタックセマンティクスを使用することです。

多くのクラスは同じA ^ポインタを保持することができます。どのクラスがデストラクタを呼び出すべきかを知る方法はありません。

クラスにIDisposeを実装させるデストラクターが実装されているため、警告が表示されます。これにより、決定的な仕方でクリーンアップする機会が与えられます。

だけでGCは無いの参照を持つオブジェクトを収集し、ファイナライザを呼び出すことができます。これは決定論的ではありません。クリーンアップを行うためにファイナライザを使用することは、将来的には長い時間と呼ばれるかもしれないので、セーフティネットだけでなければならないことに注意してください。

上記のパターンを許可するようにコードを設計することをおすすめします。

+0

おかげで、それは私がシンタックスシュガーの方法を使用することができることを本当だ - 私はこれを行う場合、実際に私は(まあ、それはとにかく警告を抑制することができる)すべてのデストラクタを実装する必要はありません。しかし、ほとんどの状況では、構文sugarメソッドを使用することはできません。管理された参照ポインターしか格納できません。管理対象オブジェクトを破棄するために、GCが管理参照ポインタを削除するための明示的な呼び出しを必要とする理由を知りたい。 – demoncodemonkey

+0

"多くのクラスが同じA ^ポインタを保持できるため、デストラクタを呼び出す必要があるかどうかを知る方法がありません" <<どのGCが最後のものかを知ることができなければならず、最後のものが解放されたらデストラクタを呼び出す必要があります。 GCがそれほど驚くべきものではないと思われます。 – demoncodemonkey

+0

あなたの言ったように私のコードをリファクタリングできるかどうかチェックします。 – demoncodemonkey

関連する問題