アプリ版:「スタンプのみでお礼する」機能のリリースについて

多次元配列のメモリ解放についてです。
以下のような方法で多次元配列を確保した場合に、
---
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; が必要なく危険な領域まで解放しようとしているということはないでしょうか?

ご専門、お詳しいかたコメント宜しくお願いします。

A 回答 (5件)

> それを考えると以下の方法であっても、


> 例外が送出される場合があるのではないでしょうか?
> char (*pMain)[20] = new char[3][20];

例外が送出される可能性はあります。
しかし、上の場合では、メモリの割り付けに成功するか、例外が送出されてメモリがまったく割り付けられないかのどちらかですので、中途半端な割付けが行われてメモリリークすることがありません。

この回答への補足

ご回答ありがとうございます。
"中途半端な割付け"の意味をいろいろ調べていて、
連絡遅れてしまいました。
調べても全く違いが分からなかったのですが、
(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次元配列の違いしか私には分からないのですが、
その違いでメモリ割り当て方法が大きく変わってくるのでしょうか?

補足日時:2008/09/17 23:44
    • good
    • 0

> (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'));

とでもすればよいでしょう。
これなら可変サイズにも対応できますし、明示的な解放が不要になります。
    • good
    • 0
この回答へのお礼

ご回答ありがとうございます。
new / deleteというものをよく知らず、
用語をググりながら内容理解しました。
メモリ不足なり、何らかの理由でメモリアロケートに失敗し、
例外が起こる可能性があり、チェックが必要ということですね。

それを考えると以下の方法であっても、
例外が送出される場合があるのではないでしょうか?
char (*pMain)[20] = new char[3][20];

着目点が間違っていますでしょうか?

お礼日時:2008/09/10 00:19

結論としては、お示しのコードで問題ありません。


以下、ちょっと細かく解説します。

まず、「new char*[3];」は「多次元配列」ではなく「ポインタの配列」を確保していることに気をつけてください。
両者はメモリ上のデータ配置が全く異なります。

前者はある空間に char が3×20並んでいることになりますが、後者はアドレス値が三つ並んでいるにすぎません。

そして「new char[20];」の繰り返しで得られるポインタ群は連続している空間を指しているとは限らず、ましてや「new char*[3];」とは全く関係のない場所である可能性もありえます。

そう考えると、「delete [] ppMain[i];」の時点では各「new char[20];」で確保した部分を開放しており、「delete [] ppMain;」では「new char*[3];」で確保したところを開放していることが理解しやすいと思います。
    • good
    • 0
この回答へのお礼

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

お礼日時:2008/09/07 00:23

解放側は問題ありませんが、割付け側に問題があります。



char** ppMain;
ppMain = new char*[3];
for (int i = 0; i < 3; i++){
ppMain[i] = new char[20]; // (1)
}

(1)の場所で例外が送出されると、確実にメモリリークが発生します。
    • good
    • 0
この回答へのお礼

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

お礼日時:2008/09/06 23:57

うい. それで OK.

    • good
    • 0
この回答へのお礼

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

お礼日時:2008/09/07 00:23

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!