- ベストアンサー
メモリ確保エラー時の効率的な書き方
mallocなどで複数の変数に対してメモリを確保する場合があると思います.例えば3つの変数の場合, char *a, *b, *c; a = (char *)malloc(100); if(a==NULL){ /* メモリ確保できなかったとき */ return (-1); } b = (char *)malloc(100); if(b==NULL){ free(a); return (-1); } c = (char *)malloc(100); if(c==NULL){ free(a); free(b); return (-1); } 変数が多くなるにつれて後から確保する変数のエラー処理(すでに確保したメモリのfree)が増えてしまうので,何か良い方法(コードが短くなるような)はないでしょうか?
- みんなの回答 (4)
- 専門家の回答
質問者が選んだベストアンサー
エラーで帰る時も正常で帰る時も、必ずどこかで確保したメモリを開放する筈です。 だったら「関数の出口」を1つにして int ret; char *a = *b = *c = NULL; a = (char *)malloc(100); b = (char *)malloc(100); c = (char *)malloc(100); if (a && b && c) { //正常に確保出来た時の処理 ret=0; } else { ret=-1; } if (a) free(a); if (b) free(b); if (c) free(c); return ret; と書けばスッキリします。freeしている場所も「1ヶ所だけ」なので「freeし忘れ」も防げます。
その他の回答 (3)
- TERABIT
- ベストアンサー率44% (4/9)
こんなのでもいいかも。 #include <stddef.h> char *a = NULL, *b = NULL, *c = NULL; // どう処理するか考えるのが面倒なので、ぐろーばるにしている。 int foo() { a = (char *) malloc(100); b = (char *) malloc(100); c = (char *) malloc(100); if (a == NULL || b == NULL || c == NULL) { free(a); // どうせ、free(NULL) は、何もしないから free(b); // 全部 free してしまうのも簡単でいいかと。 free(c); // ANSI 準拠してない昔の free() では問題ある事も a = b = c = NULL; return -1; } return 0; } 前の、誰かのソース参考(^^; その前にあった、配列にとってと言うのも、やり方によっては良さそう
お礼
回答ありがとうございます. 参考にさせていただきます.
- S117
- ベストアンサー率40% (18/45)
少なくともfreeをいろんなところでやるのだけは避けるべきです。 以下の方法を検討してみてください。 (すべての例において、関数終了時に確保されたメモリを解放するという想定で書いています。) 例1) 関数末尾に解放処理をまとめておき、gotoで解放処理へ飛ばす。 int func(size_t s) { char *a, *b; int ret = 0; a = malloc(s); if(!a) { ret = -1; goto ERR_A; } b = malloc(s); if(!b) { ret = -1; goto ERR_B; } /* 処理本体 */ ERR_B: free(b); ERR_A: free(a); return ret; } 利点:インデントが深くならない。 mallocとfreeのあるインデントレベルがそろう。 欠点:goto先を間違える恐れ。一部goto根絶派に嫌われる。 例2) if文で正常時をネストする。 int func(size_t s) { char *a, *b; a = malloc(s); if (a) { b = malloc(s); if (b) { /* 処理本体 */ free(b); } else { ret = -1; } free(a); } else { ret = -1; } return ret; } 利点:gotoがない。 欠点:インデントが深い。 mallocとfreeのあるインデントレベルがそろわない。 例3) C99なら。 int func(size_t s) { int ret = 0; char a[s]; char b[s]; /* 処理本体 */ return ret; } 利点:mallocじゃないので、freeが不要。 欠点:スタックにとるので大きすぎるとスタック不足でプログラムが停止する。これの処理について統一された方法はない。 関数からポインタを返す場合への応用ができない。 例4) C++なら(newが例外を出す場合) int func(size_t s) { int ret = 0; std::auto_ptr<char> a(new char[s]); std::auto_ptr<char> b(new char[s]); /* 処理本体 */ return ret; } 利点:すっきりしたコード。例3よりも柔軟に使える。 欠点:C++なので、Cでは使えない。
お礼
いろいろな方法があるのですね. 詳細に説明していただきありがとうございます.
- hidebun
- ベストアンサー率50% (92/181)
ポインタ配列か何かに確保したポインタを入れておいて、 エラーが起きたら、gotoでエラー処理に飛んで まとめて開放すればよいのではないでしょうか。
お礼
回答ありがとうございます. 個人的にはあまりgoto文を使いたくないです. 他に良い方法がなければこの方法にしてみます.
お礼
回答ありがとうございます.とてもすっきりしてますね. 参考にさせていただきます.