Linuxを中心とした話題を投稿予定。 使用ディストリビューションであるFedoraが中心になると思われます。http://oedipa.wiki.fc2.com/にてTips Wikiを公開してます。
どうやらだめらしい
昨日のポストで書いたコードですが、どうやらメモリリークの原因となりそうです。やっぱり、どんな形であれmalloc/newしたならfree/deleteしなさいということらしいですね。

安易に領域を確保してreturnするような関数を書いて利用するなってことですか。やはり自分でメモリ管理をするのは苦手です、トホホ^^;

というか、newやdeleteも演算子であるため、オーバーロードが可能であることに驚き。さらに、メモリリークについて調べていて参考にしたサイトには
「C++ならば自分の扱うクラス全てを派生させるスーパークラスがあるだろう。と言うか、普通はそのように実装する」
って書いてあってびっくり。マジすか。いわゆるJavaで言うところのObjectクラスを自前で用意するのがC++プログラマにとっては常識だったんすか。己の至らなさに目からウロコですよOrz

けど確かに理には適ってるな。なるほどさすればスーパークラスのnewとdeleteをオーバーロードして、確保と解放がきちんと対になっているかを調べられるように実装するのは可能だよな。JavaやC#のガベッジコレクションも考え方の基本はここにあるのかも知れない。

ただ、C++にて配列を確保したり解放した場合は問答無用でグローバルなnewとdeleteが呼ばれるらしい。自前のクラスの配列を用意したときなどはきちんと解放されているかを自分で管理しなくてはいけないのはCと同じところか。

もうちょっとこのことについて気付いていれば今回のC#からC++へのプログラムの移植でもスーパークラスについて考えておいたんだけどなぁ。まぁまだデッドラインまでは時間もあるし、考慮してみるのも面白いかも知れない。

別に凝った機能が必要なわけではないモノね。まーnewとdeleteのオーバーロードあたりでも用意してやりましょうか。仮想関数にしないとまずそうやな。というかそのスーパークラス自体が仮想クラスにしておかないとまずいか。仮想クラスにしたらそこに含まれるメソッドは自動的に仮想関数になると思っていていいのかしら・・・?

もうちょいとC++を勉強する必要がありそうだな、うん。
スポンサーサイト



前々から疑問だったのですが
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できるような実装にしとくべきだろうなぁ。

どういうキーワードで探したらヒントになる実装見つかるかしら?