• 締切済み

多次元配列のメモリ解放

多次元配列のメモリ解放についてです。 以下のような方法で多次元配列を確保した場合に、 --- char** ppMain; ppMain = new char*[3]; for (int i = 0; i < 3; i++){ ppMain[i] = new char[20]; } --- メモリ解放する場合、 --- for (int i = 0; i < 3; i++){ delete [] ppMain[i]; ppMain[i] = NULL; } delete [] ppMain; ppMain = NULL; --- で良いでしょうか? おそらく、new/deleteの回数が同じであれば問題ないと思うのですが。 少し混乱してしまって、 delete [] ppMain[i]; によって new char*[3]で確保したところも解放されており delete [] ppMain; が必要なく危険な領域まで解放しようとしているということはないでしょうか? ご専門、お詳しいかたコメント宜しくお願いします。

みんなの回答

  • jacta
  • ベストアンサー率26% (845/3158)
回答No.5

> それを考えると以下の方法であっても、 > 例外が送出される場合があるのではないでしょうか? > char (*pMain)[20] = new char[3][20]; 例外が送出される可能性はあります。 しかし、上の場合では、メモリの割り付けに成功するか、例外が送出されてメモリがまったく割り付けられないかのどちらかですので、中途半端な割付けが行われてメモリリークすることがありません。

ring_rollo
質問者

補足

ご回答ありがとうございます。 "中途半端な割付け"の意味をいろいろ調べていて、 連絡遅れてしまいました。 調べても全く違いが分からなかったのですが、 (1)の場合の中途半端な割付けというところをもし良ければ 少しコメントいただけないでしょうか? ■(1) for (int i = 0; i < 3; i++){ ppMain[i] = new char[20]; } ■(2) char (*pMain)[20] = new char[3][20]; jactaさんの回答では、 (2)の場合は、割付けに失敗すればNULLが返って来るので問題ない。 (1)の場合には割付けに失敗してもNULLが返ってこない(適当なアドレスが返ってきてしまうので例外チェックも必須)ということだと思いますが、 その違いは何でしょうか? (1)と(2)の違いというと1次元配列、2次元配列の違いしか私には分からないのですが、 その違いでメモリ割り当て方法が大きく変わってくるのでしょうか?

  • jacta
  • ベストアンサー率26% (845/3158)
回答No.4

> (1)の場所で例外が送出? > というのはどういうことでしょうか? メモリの割付けに失敗した場合、newはstd::bad_alloc例外を送出します。 その場合、既に割付け済みのメモリブロックは解放の機会を失いますので、メモリリークにつながります。 これの回避は面倒ですが... char** ppMain; ppMain = new char*[3]; std::fill_n(ppMain, 3, 0); try{  for (int i = 0; i < 3; i++){   ppMain[i] = new char[20];  } } catch (std::bad_alloc&){  for (int i = 0; i < 3; i++){   delete[] ppMain[i];  }  delete[] ppMain; } のようにする必要があります。 これが面倒であれば、 char (*pMain)[20] = new char[3][20]; とすれば、簡単になります。 ただし、ポインタ配列ではないのでサイズは固定です。 更に簡単にするには、 std::vector<std::vector<char> > vMain(3, std::vector<char>(20, '\0')); とでもすればよいでしょう。 これなら可変サイズにも対応できますし、明示的な解放が不要になります。

ring_rollo
質問者

お礼

ご回答ありがとうございます。 new / deleteというものをよく知らず、 用語をググりながら内容理解しました。 メモリ不足なり、何らかの理由でメモリアロケートに失敗し、 例外が起こる可能性があり、チェックが必要ということですね。 それを考えると以下の方法であっても、 例外が送出される場合があるのではないでしょうか? char (*pMain)[20] = new char[3][20]; 着目点が間違っていますでしょうか?

  • iiroty
  • ベストアンサー率25% (3/12)
回答No.3

結論としては、お示しのコードで問題ありません。 以下、ちょっと細かく解説します。 まず、「new char*[3];」は「多次元配列」ではなく「ポインタの配列」を確保していることに気をつけてください。 両者はメモリ上のデータ配置が全く異なります。 前者はある空間に char が3×20並んでいることになりますが、後者はアドレス値が三つ並んでいるにすぎません。 そして「new char[20];」の繰り返しで得られるポインタ群は連続している空間を指しているとは限らず、ましてや「new char*[3];」とは全く関係のない場所である可能性もありえます。 そう考えると、「delete [] ppMain[i];」の時点では各「new char[20];」で確保した部分を開放しており、「delete [] ppMain;」では「new char*[3];」で確保したところを開放していることが理解しやすいと思います。

ring_rollo
質問者

お礼

ご回答ありがとうございます。 多次元配列だと、こんな感じのことですね。 char hairetu[][][]; 失礼しました。 ポインタの配列のみを解放しているという感じが不安でした。

  • jacta
  • ベストアンサー率26% (845/3158)
回答No.2

解放側は問題ありませんが、割付け側に問題があります。 char** ppMain; ppMain = new char*[3]; for (int i = 0; i < 3; i++){ ppMain[i] = new char[20]; // (1) } (1)の場所で例外が送出されると、確実にメモリリークが発生します。

ring_rollo
質問者

お礼

ご回答ありがとうございます。 (1)の場所で例外が送出? というのはどういうことでしょうか? よろしくおねがいします。

  • Tacosan
  • ベストアンサー率23% (3656/15482)
回答No.1

うい. それで OK.

ring_rollo
質問者

お礼

ご回答ありがとうございます。