- ベストアンサー
メモリ開放の質問ですが
#include<iostream> using namespace std; void main(void) { int i; char *s,*t; s=new char[9];t=s; for(i=0;i<9;i++)*(s+i)=i; for(i=0;i<9;i++)cout<<(int)s[i]<<endl; delete s; delete t; //error } において2回目のdelete tでエラーになりますが #include<iostream> using namespace std; void main(void) { int i; char *s,*t; s=new char[9];t=s+2; for(i=0;i<9;i++)*(s+i)=i; for(i=0;i<9;i++)cout<<(int)s[i]<<endl; delete t; delete s; } はエラーになりません (s=t+2をs=t+1に変更するとエラーになる) 実際にdeleteは何を行いエラーを引き起こすのでしょうか? エラーになるメカニズムを教えてください
- みんなの回答 (6)
- 専門家の回答
質問者が選んだベストアンサー
文法上できません。 また、mallocを使っても, s=(char *)malloc(9);t=s+2; free(t);free(s); のような使い方はできません。 エラーが発生しないことがありますが、たまたまです。 異常な動作をしたが、見かけ上は正常に動作したように見えるだけです。 エラーが起きなかったのは正しいという保証にはなりません。 実際,malloc()やfree()が何をしているかがわかると、 こういうことをすると異常な動作をおこすことがわかると思います。 例えば,char buff[BUFSIZE];というテーブルから、 メモリを確保,開放するmalloc(),free(),realloc()を作ることを考えて見て下さい。 途中でfreeできるようにもできないことは無いと思いますが、オーバーヘッドが大きくなりすぎて実用的には使えないでしょう。 また、どこかでmalloc(),free(),reallo()のソースを読んでみてもわかるでしょう。
その他の回答 (5)
- zabel_metal
- ベストアンサー率38% (193/504)
単にメモリー解放をしたいだけならば既存のソフトを使用してはいかが?僕は「びーめむ」を使っている。 その他に[CoolMemory 1.0],[MemClean 1.03],[MemSouji 1.00]全てフリーウェアです。
- mitoneko
- ベストアンサー率58% (469/798)
#3に補足しておきます。 ソースから見た答えは、まぁ、#2・#3のとおりなわけですが・・・ ここからは、アブケーションとOSに依存する話です。 あなたは、ほんとうに、連続したメモリーアドレス空間を確保した上で、任意のメモリーアドレスを解放する必要があるのでしょうか?BCC++でコンパイルしていると言うことは、多分、OSは、windows95以降だと思いますが、windowsのアプリでそんな器用なメモリーアドレス管理が必要なことは・・・無いような気がします。もしこれが本当に必要なら、OSのメモリー管理APIを直接操作してメモリーを操作するべきです。 あるオブジェクト(まぁ、intでもcharでも任意のクラスでもかまいませんが)がいくつかあって、これの個数も判らず、確保と解放の順番も不明と言うのであれば、配列でメモリーを確保するのが、多分間違っています。リンクリスト(双方向か片方向かは、アプリケーション次第です。)で管理するものでしょう。 あるバッファ領域があって、その必要なバッファ領域の大きさが変動するのであれば、必要と思われる最大の領域を確保して、その領域をそのまま利用するか、vectorクラスの利用を検討するのが簡単でしょう。(タイムリーに領域を縮小しOSに返却する必要は、多分ないでしょう。ほんとに必要ですか?) 何にせよ、配列の一部を開放するという発想から離れた方がよろしいかと・・・
- mitoneko
- ベストアンサー率58% (469/798)
まず、#1の補足に書かれたソースも、致命的なエラーです。その後に、何もやっていない単なるテストプログラムだから動いているように見えるだけです。(delete2行の後にsの周辺に何か確保していろいろとやってみると良いです。まぁ、まともに動くことはないでしょう。) >1つの大きなメモリを確保してそれを少しづつ部分的に開放したいのでこのような開放の仕方をできるかどうかテストしているのです new deleteでは、このようなメモリーの確保・解放はできません。ついでにいうと、malloc・freeの組み合わせでも不可です。(場合によってはreallocが使えることがありますが、おそらく今回の場合は適用できません。) そもそも、このように、少しづつ部分的に解放するなどという用途が必要なら、自分が必要とする最小のブロックでメモリー確保を繰り返し、そのメモリーのリストを自分で管理して、不要になったブロックから、一つづつ解放していくものでしょう。(それなら、new deleteでも、malloc・freeでも可能です。) 実際に、どんな用途で、メモリーを解放するのかよくわかりませんが、少なくとも、配列に確保されたメモリーの一部を開放するような方法は、CにもC++にも無いと思います。(STLのvectorクラスならまだ目がありますが・・・ただ、これは、メモリー確保・解放に関しては、完全にライブラリーに任せるのが基本です。そんなにきめ細かくメモリーの確保や解放を気にするためのものでもないですし、コントロールもできません。もっとも、大概の用途においてそれでも全然差し支えないわけですが。)
- taka_tetsu
- ベストアンサー率65% (1020/1553)
>1つの大きなメモリを確保してそれを少しづつ部分的に開放したいのでこのような開放の仕方をできるかどうかテストしているのです そんな解放はできません。 そもそも、動的に領域のサイズを変化させたいのであれば、newではなくmalloc、reallocでしょう。 newはクラスのインスタンスを生成し、コンストラクタを呼ぶものです。deleteは、newで作成したインスタンスを破棄し、デストラクタを呼んで領域を解放するものです。 バッファの確保等の用途に使うものではありません。(使えますが)
- mitoneko
- ベストアンサー率58% (469/798)
致命的な文法違反があります。 そのため、エラーになるメカニズムもなにも・・・と言ったクラスです。 s=new char[9]; に対応するdelete文は、 delete [] s; です。 配列のメモリー領域を、単なるdeleteで解放してはいけません。 これは、上のプログラムも下のプログラムも両方とも同じエラーを起こしています。そして、このミスが、さらに悪いことに、下のプログラムでエラーが「発生しない」原因です。(そう。エラーが発生「しない」のがすでにおかしいのです。) また、newで確保したメモリーは、必ず1回「だけ」deleteしなくてはなりません。 ポインターtは、ポインターsの単なるコピーですから、sに対してdeleteした後に、tのdeleteをするということは、同じメモリーに対して二度deleteをしていることになります。(ポインターのコピーというのは、そういうことです。)これは絶対にやってはいけません。 下のプログラムで運悪くエラーが発生しなかった原因は、ほとんど調査の意味がありません。その理由は、配列をnewで確保した後、その配列をdelete []ではなくdeleteで解放した場合のプログラムの挙動は「不定」だからです。(コンパイラは、これを考慮する必要が無く、万が一このような事態があった場合は、なにをやらかしてもかまわないという意味です。辛辣な書籍に言わせれば、この場合は、コンパイラーはHDDのフォーマットを始めるコードを生成してもかわまないとまで書いた本もあります。) ここで、プログラムが終了しているから良いようなものの、sの付近のメモリーは、多分カオス状態ですから、これ以降は、もう何が起こっても不思議ではありません。 最後に、もう一度結論を。 deleteは、newで確保されたメモリーを解放します。 delete []は、newで確保された配列メモリーを解放します。 s = new char[9]; と確保した配列領域は、必ず、「一度だけ」 delete [] s; で解放しましょう。 ポインターをコピーした場合は、同じ領域を二度deleteしないように注意しましょう。コピー元とコピー先の両方でdeleteしてはいけません。
補足
ありがとうございます #include<iostream> using namespace std; void main(void) { int i; char *s,*t; s=new char[9];t=s+2; for(i=0;i<9;i++)s[i]=i; for(i=0;i<9;i++)cout<<(int)s[i]<<endl; delete []t; delete []s; } もエラーが発生しません コンパイラはBorland C++5.51ですがコンパイラの問題ですか? 1つの大きなメモリを確保してそれを少しづつ部分的に開放したいのでこのような開放の仕方をできるかどうかテストしているのです
お礼
まとめてありがとうございます 方針を変えてオーソドックスに new-deleteの1対1対応の開放をしようと思います 若干管理が大変になりますがそれほどでもないのでそうしようと思います