2011-12-06 19 views
2

は私がC++クラスに次のコンストラクタを持っていると仮定したときにローカル・バッファの解放:は、C++で例外をスローが

MyClass::MyClass() 
{ 
    char* buffer = malloc(100); 
    if (0 != someD3DXCallThatCanFail(..., buffer, ...)) 
    { 
     free(buffer); 
     throw MyException(L"some message"); 
    } 
    char* buffer2 = malloc(200); 
    if (0 != anotherD3DCallThatCanFail(..., buffer2, ...)) 
    { 
     free(buffer); 
     free(buffer2); 
     throw MyException(L"another message"); 
    } 
    .. more code here where buffer and buffer2 are still used 

    free(buffer); 
    free(buffer2); 
} 

編集:私はmalloc関数/自由で新しい嫌い/削除を行うが、残念ながら私はバッファを使用する必要がありますテクスチャを読み込み、ID3D10ShaderResourceView、ID3D10Buffer、頂点バッファなどに渡します。これらはすべて、バッファへのポインタを必要とします。

エラーコードを返す代わりに例外を使用するために何をしようとしていますか。 また、バッファが必要な場所に作成し、不要になった直後にバッファを解放したいと考えています。

しかし、エラーの場合、エラーコードを返したり例外をスローしたりしても、その時点までに作成されたバッファはすべてクリーンアップする必要があります。 10個のバッファと10個のエラーポイントがある場合は、free()を100回呼び出す必要があります(エラーごとに各バッファを解放することを忘れないでください)。

私の同僚は、あるロジックを変更したいと思います。たとえば、真ん中の別のバッファを追加したいとします。今度は、メソッドの残りの部分で起こりうるすべてのエラーを見て、そのような場所にそのバッファのfree()を追加する必要があります。彼が急いでいる場合、彼は簡単にそのような場所をいくつか見落とすことができ、あなたはメモリリークを持っています。

これもコードを非常に大きくします。

finallyキーワードは、JavaまたはC#でこの問題を解決します。コード内のどこで例外が発生しても、私はまだ "finally"のすべてのバッファをクリーンアップします(ガベージコレクションでは必要ありません)。私が理解しているところからC++では、そのようなバッファのメンバ変数を作成しなければならないかもしれませんし、デストラクタでバッファがクリーンアップされていることを確認してください。 "pBuffer"という名前のメンバ変数は、私的なものであっても、1つのメソッド(この場合はコンストラクタ)でのみ使用され、常にNULLになりますので、私にとってはかなり醜いと思われます。時間。

一般的な問題である必要がありますが、検索を使用して回答を見つけることはできませんでした。ありがとう!

+4

絶対に必要でない限り、C++で 'malloc/free'を使用する習慣から脱出する必要があります。代わりに 'new/delete'を使うことをお勧めします。 –

+2

真実ですが、 'new/delete'を使用しない方がいいです:)コンテナやスマートポインタなどを使って手動でメモリを管理しないようにします。彼らは例外安全性を保証することをずっと容易にします。 –

+1

@Dave - それをやったら、さらに簡単な人生のためにスマートポインタを使って 'new'と' delete'を避けてください –

答えて

8

手動でメモリを管理しなくても、このような問題は発生しません。 std::vector<char>のようなものを使用してください。

代わりに、ブーストのshared_arrayのようなものを使用することができますが、それはあなたがここで何をしようとしては過剰だ:

http://www.boost.org/doc/libs/1_41_0/libs/smart_ptr/shared_array.htm

ここで行われるより一般的なポイントは、あなたが使用する必要があるということですRAIIイディオム - つまり、リソースを取得すると、デストラクタがそれらを再び解放するクラスのインスタンスにそれらを格納します。しかし、そのリソース所有クラスのインスタンスが範囲外になると、そのリソースは解放されることが保証されます。 、

代わり

http://en.wikipedia.org/wiki/Resource_Acquisition_Is_Initialization

4

標準的な答えは、「Resource Acquisition Is Initialization」(RAII)とスマートポインタの原則です。スタック上に、デストラクタ内のメモリを解放するクラスインスタンスを作成します。 boost::scoped_ptr

+0

ありがとう、私は今あなたと他人の答えからRAIIの考えを理解しています)) – iseeall

1

これには慣用的なC++アプローチを使用してください:RAII。このウィキペディアのページにはC++のサンプルがあります。

1

"C++スマートポインタ"を再度検索します。 mallocの代わりにメモリに例外安全なラッパーが必要です。注意しておきましたように、多くの頭痛を招きます。operator newによって置き換えられる可能性があります。

前の質問hereがこの領域をカバーしています。

2

raiiを使用します:

はこちらを参照してください

MyClass::MyClass() 
{ 
    std::vector<char> buffer(100); 
    if (0 != someD3DXCallThatCanFail(...)) 
    { 
     throw MyException(L"some message"); 
    } 
    std::vector<char> buffer2c(200); 
    if (0 != anotherD3DCallThatCanFail(...)) 
    { 
     throw MyException(L"another message"); 
    } 
    .. more code here 
} 
1

このため標準的な答えはC++ 11にunique_ptrをされます。これまでは、シングルトンの場合はscoped_ptr(http://www.boost.org/doc/libs/1_47_0/libs/smart_ptr/scoped_ptr.htm)、scoped_array(http://www.boost.org/doc/libs/1_47_0) /libs/smart_ptr/scoped_array.htm)、どちらもBoostからの配列です。または、それと同等のコードを自分で作成することもできます。

関連する問題