• ベストアンサー

delete演算子によるメモリ解放について

MFC MDIプログラミングで、 Genericクラスで点、線、面クラスを作って、 オブジェクトを組み合わせて 3次元図形を作っています。 図形を削除する際、 delete演算子で各オブジェクトの メモリ解放をプログラムしています。 例) delete m_pLine; delete m_pSurface; しかしながら、これらポインタの中には、 アルゴリズム上、既にdeleteされているものもあるため、 既にdeleteしたオブジェクトを更に deleteしようとして 実行時エラーを生じてしまいます。 deleteする前に、 当該ポインタが既にdeleteされているかどうか 判定する関数等あれば if文で回避できると思うのですが、 何か良い方法がありますでしょうか? よろしくお願いします。

  • zico
  • お礼率60% (48/80)

質問者が選んだベストアンサー

  • ベストアンサー
  • MAGI
  • ベストアンサー率45% (5/11)
回答No.2

if (m_pLine != NULL) { delete m_pLine; m_pLine=NULL; } とすれば、どうでしょう

その他の回答 (3)

  • hyde-la
  • ベストアンサー率28% (42/146)
回答No.4

結構嫌な問題ですね。 生成する前にNULLで初期化しておいて・・・・というのが 定石的な方法でしょうか。 deleteした後もポインタにNULLを入れておく、ということで。 その約束の上でなら、NULLかどうかの判定が出来ます。 それ以外によい方法があるなら・・・私が知りたいです(笑 他にもいくつか方法はありますが、どれもお勧め出来る方法じゃ ありませんので・・・。

zico
質問者

お礼

ご連絡が遅くなりましてすみません。 hohihohiさん、MAGIさん、selenityさん、hyde-laさん 昨年は、未熟な自分に ご指導ありがとうございました。 さて、皆様のご指摘のおかげで、 問題が2つあることがわかり、 無事解決することができました。 1つは、同一ポインタの2重メモリ解放で ポインタにNULL値を設定することで、 無事解決できました。 もう1つは、 2つ以上のポインタが同一の実体(アドレス)を 参照している場合 (2つの面が同一の辺を共有している場合等)で、 hohihohiさんのご指摘のとおり、 アルゴリズムに問題があり、 1つがdeleteされたら、 共有ポインタ全てにお知らせすることで、 解決することができました。 本当にありがとうございました。 本年もご指導よろしくお願い致します。 ポイントにつきましては、 MAGIさん,selenityさん、hyde-laさんの 3方につきましては、 同様のアドバイスでしたので、 最速のMAGIさんということでご了承願います。 (気持ち的にはみなさんに登録したいのですが。。。)

  • selenity
  • ベストアンサー率41% (324/772)
回答No.3

簡単な回避方法としては、 delete実行直後に、変数にNULLを代入すれば良いと思います。 例) if(m_pLine){ delete m_pLine; m_pLine=NULL; } if(m_pSurface){ delete m_pSurface; m_pSurface=NULL; }

  • hohihohi
  • ベストアンサー率34% (23/66)
回答No.1

それは、そもそもアルゴリズム的に間違えているような気がします。 zico さんがソフト開発に関してどの程度のレベルの方かわかりませんが、仮に初心者でしたら、この場合、明らかにプログラムの方針そのものが間違いなので、多重 delete しないような作りに書き直すべきです。

zico
質問者

お礼

ご連絡が遅くなってすみません。 年末サーバーがダウンしてしまいまして。。。 アドバイスありがとうございました。 おかげさまで、NULL値設定とともにアルゴリズム改良によって 解決することができました。 本年もご指導よろしくお願いします。

関連するQ&A

  • delete[]と、delete演算子の明確な違いとその使い分けについて

    C++の delete[]と、delete演算子の明確な違いとその使い分けについて 型* ptr = new 型[要素数]; でnewしたものについては、 delete[] ptr; にて、開放 型* ptr = new 型(); でnewしたものは、 delete ptr; するものだと、覚えてました、 特に深くは考えていなかったのですが。 std::auto_ptr<T> では、内部的には、delete[]ではなく deleteをしているという文章を見ました。 { std::autoptr<型A> iptr; iptr = new 型A; } のようなときは いいのですが・・・ { std::auto_ptr<char> cptr; cptr = new char[n+1]; } のようなときは、 動的配列なので、内部的に delete ptr; になってしまいます。 このように、テンプレートクラスを自作するときに 実際の特殊な型が決定されるまで、 deleteで、いくのかdelete[]でいくのか決定できないのはつらそうです。 そこで、deleteと、delete[]の正しい意味を 知りたいのですが。 Javaや、.NETには、配列オブジェクトというものが あります。 C++で、 new char[n+1]; は配列オブジェクトでしょうか? だとすると、delete[]は 右に来たものが配列オブジェクトなら、 Lengthを(こんなものがあるとして)調べて 1つづつ、まわして、deleteのほうを使ってひとつひとつ開放していく。 右に来たものが配列オブジェクトでなければ deleteと同じ振る舞いをする。 という動きが物理的に考えれそうで。 delete[]と書いておけば、状況に応じて、 動的配列なら全要素サーチして、開放そうでなければ deleteという風に、勝手に自動でそうしてくれるなら、 どんなときでも、delete[]にするようにコードを書いておけばよさそうです。。 実際のところどうなんでしょうか? deleteと、delete[]の明確な意味の違いと、 使用方法の違いについて教えてください。

  • 【C++】new/deleteについて

    deleteについていまいち解らないことがいくつかあります 1 deleteしたポインタを再びnewで確保して使用してもいいのか 2 newしたものは(例えば)関数を抜ける際必ずdeleteするべきなのか それとも抜ける時に自動的に解放されるのか 3 動的オブジェクトの場合も中で動的確保したものを全てdeleteしてからdeleteするべきなのか 何卒よろしくお願いいたします。

  • C++でのクラスオブジェクトの破棄

    こんにちは。 C++では、プログラムの終了時に、全てのクラスオブジェクトは、デストラクタが呼び出されて破棄されますが、プログラムの途中で、クラスオブジェクトを明示的に破棄する方法はあるのでしょうか? 例えば、new演算子によってメモリを動的に割り当てたポインタなら、delete演算子で破棄できますが、 クラスオブジェクトにdelete演算子は使えないようです。 何かいい方法を知っておられる方がいらっしゃれば、是非アドバイスを頂きたいと思います。

  • c言語 等価演算子(==)について

    等価演算子(==)は、ポインタの指すオブジェクトが同一あるかないの判定する演算子。  故に下記の例、*sc1 == sc2 は、sc1とsc2の値(オブジェクト)を比較しているのですか教えてください。      char *sc1 = s1; char *sc2 = s2; *++sc1 == sc2;

  • メモリリークが発生するのはどういうときですか?

    メモリが解放されずに残るケースというのは、どういうときがあるのでしょうか? ※asp.netでプログラムを書いています。 (1)どのクラスも、基本的にコンストラクタでメモリが確保され、 どのクラスも、その親のオブジェクトが解放されたら、自分自身のメモリも解放される。 よって、画面のCloseで、すべてのオブジェクトのメモリは解放される。と思っています。 (2)スタティックメソッドで、参照渡しの引数があるとき、何度そのメソッドを使っても、 オブジェクトのポイントが渡るだけだし、処理完了後は、そのポインタすらも解放すると思っています。 (3)画面右上の「×」のボタン以外で画面が閉じてしまったとしても、セッションタイムアウトになった時点で、その分のメモリは解放すると思っています。 ◆どうしてdisposeメソッドがあるのでしょうか? .自分は、プログラム内に1箇所もdisposeを書く必要がないと思っていますが、どのような時に使うべきなのでしょうか?

  • C++で>>演算子のオーバーロード

    C++学習者です。 Visual Studio Community 上で、ある教本を使って勉強しています。 現在Stringというクラスを作って、文字列に対して連結や部分文字列の取り出しなどができるようにするための色々な演算子のオーバーロードをする関数を定義していますが、疑問点がありますので、お聞きしたいと思います。 Stringクラスのプライベート変数は、文字列の長さを表すlength と、new 演算子で動的に確保するメモリー領域の始まりのアドレスを表す *sPtr の二つです。 クラス内ではパブリックなメンバー関数としていろいろな演算子がオーバーロードされていて、これらについてはよく理解できるのですが、friend 関数として定義されている入力演算子(>>)について納得がいかない部分があります。 その関数は次のようになっています。 istream &operator>>(istream &input, String &s) { char temp[100]; input >> setw(100) >> temp; s = temp; return input; } わからないのは s = temp; の部分です。 sはStringクラスのオブジェクトで、temp は単なる文字列なのに、なぜ代入できるのでしょうか? 代入演算子=のオーバーロード関数も下に挙げますが、この中でも単なる文字列をStringクラスのオブジェクトに代入できるようにはなってないように見えます。 const String &String::operator=(const String &right) { if (&right != this){ // avoid assignment of itself delete [ ] sPtr; length = right.length; sPtr = new char[ length + 1]; strcpy(sPtr, right.sPtr); } else cout<< "attempted to assign a String to itself \n\n"; return *this; } どなたか答えて頂けると有難いです。

  • インスタンスオブジェクトとは何かについて教えて!!

    下記内容はあるサイトのインスタンスについての説明文です。 画像は、自分なりに理解したものです。 (1)メモリ上には記憶場所(=ポインタ)はない (2)var Aa = new Bb("13" , "smole");とscript内に追加されたことにより メモリ上に記憶場所(=ポインタ)が作成され、 BbオブジェクトつまりBb("13" , "smole");がその記憶場所(=ポインタ)に入る (3)そしてBb("13" , "smole");が入った 記憶場所(=ポインタ)にAaという名前を付ける。 考え方に間違いがあるでしょうか? ---------------------------------------------------- var Aa = new Bb("13" , "smole"); これは、BbクラスオブジェクトのBbコンストラクタをnew演算子を利用して起動しています。 new演算子は、メモリ上に記憶場所を確保して、Bbオブジェクトを作成した後、そのポインタを返す演算子です。 new演算子から返されたポインタは、Aaへ格納されます。この場合のAaをBbオブジェクトのインスタンスといいます。 また、new演算子でメモリ上に記憶場所を確保して作られたオブジェクトをインスタンスオブジェクトといいます。 つまり、 オブジェクト == インスタンスオブジェクト で、 インスタンス != インスタンスオブジェクト インスタンス != オブジェクト です。 ----------------------------------------------------

  • C++:構造体:newで入れ子:deleteは?

    C++で以下のような構造体を使っています。(本当は他にもメンバが有ります) // ----- typedef struct{  int *npMember; }Test_t; // ----- これをクラスのメンバ変数で // ----- Test_t *m_tpTestStruct; // ----- とし、関数の中で // ----- m_tpTestStruct = new Test_t[10]; for (int i = 0; i < 10; i++) {  m_tpTestStruct[i].npMember = new int[100]; } // ----- というようにメモリを割り当てています。 これを解放する時は、 // ----- for (int i = 0; i < 10; i++) {  delete [] m_tpTestStruct[i].npMember; } delete [] m_tpTestStruct; // ----- で、良いのでしょうか? それとも、他の書き方が必要なのでしょうか?

  • ◆コピコンを実装しないと、returnでエラー?

    ポインタを持ったクラスで、 コピーコンストラクタを実装していないと、 newを使用した際にエラーになるそうですが、 なぜなのでしょうか? 値渡しの関数などで、 コピーコンストラクタを実装していないと、 デフォルトコピーコンストラクタで、ポインタ型のメンバ変数の値もコピーするため、 return する前に、 「一時的な変数としてコピーされていた値渡しの引数」が、 関数の終了時に解放され、 「アドレスを指しているポインタ」が指し示す先の領域に「delete」が走ってしまうため、 呼び元の変数で持っているポインタが指し示す先の領域も、 解放されてしまうとかでしょうか?? そもそも、 ポインタ pMem=NULL は、アドレスの指し示す値のリセットで、 Delete pMem は、アドレスが指し示す先頭から、そのクラスで必要としている分のメモリ量進んだアドレスまでを、解放する。 ということで合っているでしょうか? それとも、 「ポインタ」を削除しても、ポインタの指し示す先のアドレス自体は存在していて、 「呼び元」のアドレス格納用領域と、 「関数の呼び出し時にコピーコンストラクタで作られるアドレス格納用領域」は別であり、 ポインタ自体を削除しても、ポインタの先にあるメモリ領域は残っているのでしょうか?

  • C++のnewで確保した領域について

    こんにちわ。C++を勉強し始めた者です。 new演算子を使ってインスタンスを生成した場合、それはスタックではなくヒープ領域に確保され、不要になったらdeleteを使って領域を解放しなければいけない認識です。 C++の初心者向けサンプルコードを見ていて疑問があったので質問させてください。 (例)クラスA.cpp ======================== #include <Car> #include <Garage> ~略~ クラスAのコンストラクタ{ Car *mycar = new Car("プリウス"); addGarage( mycar ); } クラスAのデストラクタ{ } ======================== 上記のような実装のクラスAがあったのですが、コンストラクタでCarクラスのインスタンス生成をして、オート変数の*mycarに格納して、Garageの公開関数に渡しています。 質問1:このクラスAをインスタンス生成した場合、コンストラクタで確保したヒープ領域は、プログラム終了時まで解放されない認識であっていますか? 質問2:オート変数の*mycarはコンストラクタからreturnした時点で解放されてしまうので、今のままではデストラクタでヒープ領域をdeleteできない認識であっていますか? 質問3:newで生成したインスタンスへのポインタは、その関数内でdeleteしない場合、メンバ変数やstatic変数、グローバル変数に格納しなければdeleteできなくなるという理解であっていますか? 質問4:C++のコードでnewした戻り値をオート変数に格納するプログラムは通常使うことはあるのですか?