2009-07-30 30 views
1

char配列の新規と削除の間に膨大なコードがあると問題になるのはなぜですか?ヒープの破損

Example

void this_is_bad() /* You wouldn't believe how often this kind of code can be found */ 
{ 
    char *p = new char[5]; /* spend some cycles in the memory manager */ 
    /* do some stuff with p */ 
    delete[] p;  /* spend some more cycles, and create an opportunity for a leak */ 
} 
+1

私はあなたが本当に求めているのかわからないんだけど。 「新規」と「削除」の間にたくさんのコードを持つことは間違っていません。ヒープの破損は、あなたが持っているコードの数にかかわらず悪いです。 – nos

+0

質問は "与えられたコードがどのようにしてリークの機会を作り出すことができるのでしょうか? – Sean

+0

これはいつかすぐに予定されている宿題問題です。 – thewillcole

答えて

0

私はそれが任意の変数の新しいと削除の間のコードの膨大な量を持っている問題ではないことを主張するだろう。新しいものを使用するという考えは、ヒープに値を置くことで、それを長時間にわたって生き続けることです。これらの値に対してコードを実行することが期待されています。

何が新しいの間で同じメソッド内のコードの膨大な量を持っているとき、あなたがトラブルに巻き込まれると、削除することができますが、誤っによるをスローされた例外

  • ...に変数を漏洩するチャンスです限り、あなたが初めか終わりを見ることができないので、人々は任意に、彼らはこれらのいずれもが、このようなRAIIタイプを使用して固定することができ、削除コール

をスキップ実現することなく途中からの復帰開始を取得

  • 方法として新しい/削除ペアの代わりに。

  • +1

    通常、std :: vectorよりむしろstd :: stringを使用します。。 – Brian

    +0

    @Brian、配列型として扱うとき、私は一貫性のためにベクトルを好むが、手動の新規/削除よりもRAII型に対して主張することはできない。 – JaredPar

    +0

    @ブライアン:ジャレッドに同意する必要があります。それは文字列ではないかもしれません。 –

    5

    あなたが参照記事は

    char p[5]; 
    

    は、このケースで同じように効果があると漏れの危険性を持っていないことをポイントになっています。

    一般に、割り当てられたメモリのライフサイクルを非常に明確にすることでリークを回避し、新しいものと削除するものが関連していることがわかります。

    2つのコードを大きく分けてチェックするのは難しいため、コードを削除する可能性のある方法がないかどうかを注意深く検討する必要があります。

    2

    そのコードのリンク(およびソース)は、そのコード内のヒープの不要な使用を嘆いています。一定のメモリ量と少ないメモリ量のために、ではなく、をスタックに割り当てる必要はありません。

    Instead

    void this_is_good() 
    { 
        /* Avoid allocation of small temporary objects on the heap*/ 
        char p[5]; /* Use the stack instead */ 
        /* do some stuff */ 
    } 
    

    最適よりもかかわらず、そのだけの少ない元のコードと、本質的には何の問題もありません。

    +0

    私はこれが好きです。次に、私はそれを参照として渡している場合は、配列の重複を避けるためにスタック内の "p"へのポインタを使用することができます。 –

    +0

    スタック変数へのポインタは私にヒービージービーを与えます。あなたは、関数が返ってきたときに生きているヒープ割り当てオブジェクトに自分自身が見つからないようにする必要があります。パラメータとして渡すと難しくなります。 –

    8

    誰かが例外をスローする可能性があるためです。
    誰かがリターンを追加する可能性があるためです。

    新しいコードと削除コードの間にたくさんのコードがある場合は、スロー/リターンの前にメモリの割り当てを解除する必要があることがわかりませんか?

    なぜあなたのコードにRAWポインタがありますか?
    std :: vectorを使用します。

    0

    なお、 "コードの巨大な断片" と仮定すると、ではない:

    1. 常に実行 "[] Pを削除します;" "p = new char [size];"を呼び出す前にまたは "例外をスローする"
    2. 常に「p = 0;」を実行します。 "delete [] p;"を呼び出した後

    最初の条件を満たすことができないと、pの内容が漏洩します。 2番目の条件を満たすことができない場合、2重削除が発生する可能性があります。一般的には、問題を避けるためにstd :: vectorを使うことが最善です。これは良いだろう場合は

    +0

    ポイント2.無価値です。これはCからの二日酔いです.C++とスコープとスマートポインタを使用すると、これは非常に必要です。 –

    +0

    ポイント2は価値がありません。 "delete [] p;"を実行してから "delete [] p;"を実行してください。再び。 delete演算子はpを0に設定しません。 –

    +0

    また、私は、std :: vectorをこの種のものに使うことをお勧めします。 (単一のオブジェクトの場合、boost :: shared_ptrが最良の方法ですが、scoped_ptrとshared_ptrは配列には適用されません)。 –

    -1

    を求めていますか?

    void this_is_great() 
    { 
        char* p = new char[5]; 
        delete[] p; 
        return; 
    } 
    

    そうではありません。特定の例では、新しい間のコードの束を有し、削除必ずしも悪いことを示すではないことを

    1

    。ヒープを使用しないコードを記述する方法がある場合は、ヒープの破損を避けることをお勧めします。

    それはまともな十分なアドバイスです。ヒープを使用する量を減らすと、ヒープが破損している場所をどこで調べるかが分かります。ヒープについて、そして新しい有し、かつ互いに近接発生削除に関するすべての興味深い答えへ次

    2

    、私は1つの関数内のコードの膨大な量を持つの膨大な事実を回避すべきであることを追加される場合があります。膨大な量のコードが2つの関連するコード行を分けると、さらに悪化します。

    私は「仕事の量」と「コードの量」を区別します:今

    void do_stuff(char* const p); 
    
    void formerly_huge_function() { 
        char* p = new char[5]; 
        CoInitialize(NULL); 
        do_stuff(p); 
        CoUninitialize(); 
        delete[] p; 
    } 
    

    do_stuffは、割り当ての問題に干渉することなく、多くのことを行うことができます。しかし、他の対称的なものもこのように一緒にとどまります。

    それはすべてあなたのコードを維持するために起こっている男についてです。 1ヶ月であなたかもしれません。

    +0

    初期化とファイナライゼーションルーチンが不良で、凝集力が低く、カップリングが高いことを除けば、しかし、機能の長さについてのあなたのポイントは、しかし、右です。 –

    +0

    @David:確かに、対称的なルーチンは、C++では、RAIIを使ってよりよく解くことができます。しかし、いくつかの言語/ライブラリ/プラットフォームにはそれがありません。 – xtofl

    関連する問題