2007年8月27日月曜日

前々から疑問だったのですが

C/C++で組んでいて、前から疑問だったことがあります。
関数内でmallocなりnewなりで配列を確保し、それをreturnで返すようなものを実装したとします。まぁベクトルの演算を実装する場合なんかが挙げられるでしょうか。具体的には
double* Plus(double* a, double*b, length)
{
double* dst = new double[length];
for(int i=0; i<length; i++)
dst[i] = a[i] + b[i];
return dst;
}
みたいな関数ですね(ホワイトスペースってHTMLでどう書くか忘れた・・・)。こう定義すると、
double* c;
c = Plus(a, b, length);
みたいな書き方ができて多少分かりやすいかなと。関数内で領域を確保するのではなく、予め用意したバッファを引数に与えて実装するという手ももちろんありますが、見た目にどれが結果を格納するバッファか分かりにくいよな、と思っちゃうんですよね。実装するならこんな感じ?
void Plus(double* a, double* b, double* dst, length)
{
for(int i=0; i<length; i++)
dst[i] = a[i] + b[i];
}
見た目だけの問題で実際の処理量や確保するメモリ量に大差はないってのは分かってるんです。ただ、前者の例だと、d=a+b+cみたいな演算をするときに
d = Plus(a, Plus(b, c, length), length);
という書き方が可能です。後者の書き方だと、b+cの結果を一旦保持した上でそれとaの結果を加える必要があるため、変数が余計に必要となります。大した手間ではないと言われたらそれまでなんですが^^;
さて、前置きが長くなりましたが、本題はここからです。C/C++の場合、malloc/newした領域は使い終わったら必ずfree/deleteしましょうというのが作法です。自己責任ですが。ですので、こうした演算処理で確保した領域も用事が済んだら解放しなくてはなりません。
問題は
d = Plus(a, Plus(b, c, length), length);
と言った書き方をした場合の処理についてです。Plus(b, c, length)の結果は変数としてはどこにも格納されていませんから、先の「d = 〜」を実行した後はそのアドレスへアクセスする手段がありません。ですので明示的にfree/deleteできません。
ならばこの処理を延々繰り返すとメモリリークをいずれ起こしちゃうんでしょうか?これが気になってるんですよねー。
JavaやC#のようなガベッジコレクションが用意されている言語なら気にしないのですが、C/C++ではどうなるんだろうと。それとも、メモリリークの原因になるからこういう実装はするなということなのでしょうか? それならそうで、仕方ないので諦めるんですが・・・。
MATLABとかOctaveってどうやって実装してるんだろうなー。あの柔軟な言語体系をどうやってC++で実装してるのか気になる・・・。
あぁ、Octaveはオープンソースだからソースコード手にはいるのか。いやさすがに見る根性ないけれど^^;
ま、当面は少々一時変数が増えようとも確実に自身でfree/deleteできるような実装にしとくべきだろうなぁ。
どういうキーワードで探したらヒントになる実装見つかるかしら?