僕はこの前、素数のプログラムについての質問に答えたが、その際に、
( ˘⊖˘) 。o(待てよ、もしかして自分のプログラムもメモリリークしてないか??)
と思い、今日実際に試してみた。すると
_人人人人人人人人人人人人人人人人人人人人_
( ◠‿◠ )☛>出力ウィンドウを99%埋め尽くすメモリリーク通知<
 ̄Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^ ̄
▂▅▇█▓▒░('ω')░▒▓█▇▅▂うわあああああああああああ
ってなった。で、その原因。
クラスのインスタンスをdeleteしてない
…orz
で、とりあえずインスタンスをちゃんと終了時にdeleteしようと思った。そして、
_人人人人人人_
>stack overflow<
 ̄Y^Y^Y^Y^Y^Y^ ̄
思わず目を疑った。そして気づいたこと。
なんでデストラクタでdelete thisしたの…呼び出されない…
ってことで、インスタンスをnewで統一して、終了処理にちゃんとdeleteを打ち込んだ。すると、
よかった…メモリリーク完全に消えた…(´・ω・`)
…以後クラスのインスタンスには気を付けようと思います(´;ω;`)
メモリリーク
- spaaaark・∀・
- 記事: 66
- 登録日時: 12年前
- 住所: 埼玉
- 連絡を取る:
メモリリーク
最後に編集したユーザー spaaaark・∀・ on 2013年8月01日(木) 17:41 [ 編集 1 回目 ]
Re: メモリリーク
デストラクタはdeleteでインスタンスを解体する際に呼び出されるので、デストラクタでdeleteすると再帰的に呼び出されてたいへんなことになります。
実体宣言したときはdeleteしなくてもデストラクタが呼び出されます。
変数のライフサイクルに対して曖昧なままnew/deleteに統一して事なきを得るというのは問題を先送りにしているだけで良くないと思います。
実体宣言したときはdeleteしなくてもデストラクタが呼び出されます。
変数のライフサイクルに対して曖昧なままnew/deleteに統一して事なきを得るというのは問題を先送りにしているだけで良くないと思います。
- spaaaark・∀・
- 記事: 66
- 登録日時: 12年前
- 住所: 埼玉
- 連絡を取る:
RE: メモリリーク
そうですよね…。一応解決してはいましたが、疑問は残っています。
ただ、クラスの中身として別のクラスの実体宣言をしていた自分の操作に引っかかっています。
つまり、それでクラスを解体するタイミングを見失ってしまい、大量のメモリリークが発生したようにも思えるのですが、違うのでしょうか。
訂正後は、取り込みたいクラスのポインタ型を使いたいクラスのメンバ変数にしましたが、これでは実体宣言されておらず、ユーザーが実体宣言を
関数内(僕の場合はコンストラクタ)で行い、デストラクタでちゃんとそのクラスを解体するようにしました。
そこで…、実体を直接宣言するのと、new演算子経由でインスタンスを生成するのでは、これってどのような違いがあって、どう使い分ければいいんでしょうかね…(´・ω・`)?
(長くなりそうなら後々掲示板にスレッド立てます。とりあえず、様子見。)
ただ、クラスの中身として別のクラスの実体宣言をしていた自分の操作に引っかかっています。
つまり、それでクラスを解体するタイミングを見失ってしまい、大量のメモリリークが発生したようにも思えるのですが、違うのでしょうか。
訂正後は、取り込みたいクラスのポインタ型を使いたいクラスのメンバ変数にしましたが、これでは実体宣言されておらず、ユーザーが実体宣言を
関数内(僕の場合はコンストラクタ)で行い、デストラクタでちゃんとそのクラスを解体するようにしました。
そこで…、実体を直接宣言するのと、new演算子経由でインスタンスを生成するのでは、これってどのような違いがあって、どう使い分ければいいんでしょうかね…(´・ω・`)?
(長くなりそうなら後々掲示板にスレッド立てます。とりあえず、様子見。)
Re: メモリリーク
クラスを解体するタイミングを見失うというのがよく分かりませんが。
適切なコードでデストラクタが適切に呼び出されないのだとしたら処理系としてかなりの問題です。
コード側に問題がある可能性がはるかに高いと思いますが。
基本型の変数の初期化のようにコンストラクタが初期化のために呼ばれます。
基本型の変数は宣言されたブロックを抜けて使えなくなりますが、使えなくなる前にデストラクタが呼ばれます。
new演算子で確保されたメモリを初期化するためにコンストラクタは呼ばれます。
delete演算子でメモリを解放する前にデストラクタは呼ばれます。
適切に対応させて使っている限り問題になることはないはずですが。
適切なコードでデストラクタが適切に呼び出されないのだとしたら処理系としてかなりの問題です。
コード側に問題がある可能性がはるかに高いと思いますが。
基本型の変数の初期化のようにコンストラクタが初期化のために呼ばれます。
基本型の変数は宣言されたブロックを抜けて使えなくなりますが、使えなくなる前にデストラクタが呼ばれます。
new演算子で確保されたメモリを初期化するためにコンストラクタは呼ばれます。
delete演算子でメモリを解放する前にデストラクタは呼ばれます。
適切に対応させて使っている限り問題になることはないはずですが。
最後に編集したユーザー ISLe on 2013年8月02日(金) 00:13 [ 編集 1 回目 ]
- spaaaark・∀・
- 記事: 66
- 登録日時: 12年前
- 住所: 埼玉
- 連絡を取る:
Re: メモリリーク
ありがとうございます。一応、「実体宣言は関数の終わりで解体され、newで生成したものはdeleteによって好きなタイミングで解体できる。」ISLe さんが書きました:クラスを解体するタイミングを見失うというのがよく分かりませんが。
適切なコードでデストラクタが適切に呼び出されないのだとしたら処理系としてかなりの問題です。
コード側に問題がある可能性がはるかに高いと思いますが。
基本型の変数の初期化のようにコンストラクタが初期化のために呼ばれます。
基本型の変数は宣言されたブロックを抜けて使えなくなりますが、使えなくなる前にデストラクタが呼ばれます。
new演算子で確保されたメモリを初期化するためにコンストラクタは呼ばれます。
delete演算子でメモリを解放する前にデストラクタは呼ばれます。
適切に対応させて使っている限り問題になることはないはずですが。
と自分なりに解釈してみましたが、こんな感じでよろしいでしょうか。もちろん、解体忘れは論外として、です。
- spaaaark・∀・
- 記事: 66
- 登録日時: 12年前
- 住所: 埼玉
- 連絡を取る:
Re: メモリリーク
ありがとうございます。調べてみたところ、解体を忘れたインスタンス等をプログラム終了時に自動的に解体してくれるSTLのようですね。naohiro19 さんが書きました:std::auto_ptr/std::shared_prtを使うとメモリリークは起こりません。
解体忘れを自動的に修復してくれそうな機能です。気になる際に使用してみようと思います。
情報提供ありがとうございました><!
Re: メモリリーク
解釈は概ね合ってます。spaaaark・∀・ さんが書きました:ありがとうございます。一応、「実体宣言は関数の終わりで解体され、newで生成したものはdeleteによって好きなタイミングで解体できる。」
と自分なりに解釈してみましたが、こんな感じでよろしいでしょうか。もちろん、解体忘れは論外として、です。
正確には関数ではなく『ブロック』が実体宣言に影響するのですが。
基本中の基本なので、自分なりではなく、規格書などの資料を調べてきちんとしっかり押さえておくべきかと思います。
『生存範囲(ライフサイクル)』は『可視範囲(スコープ)』に比べて解説記事での扱いが少ない印象を受けますけどね。
もちろんそれぞれ別物なので気を付けてください。
Re: メモリリーク
ネイティブなポインタだとポインタが指すオブジェクトの面倒を見てくれませんが、スマートポインタは『スマートポインタ自身が解体されるとき』スマートポインタが指すオブジェクトを(必要ならば)解体します。spaaaark・∀・ さんが書きました:ありがとうございます。調べてみたところ、解体を忘れたインスタンス等をプログラム終了時に自動的に解体してくれるSTLのようですね。
解体忘れを自動的に修復してくれそうな機能です。気になる際に使用してみようと思います。
情報提供ありがとうございました><!
『スマートポインタ自身が解体されるとき』がキモです。
生存範囲(ライフサイクル)をきちんと理解せず誤った使い方をすると二重解体等の極めて発見しにくいバグを生むことになります。
最後に編集したユーザー ISLe on 2013年8月03日(土) 18:44 [ 編集 1 回目 ]
- spaaaark・∀・
- 記事: 66
- 登録日時: 12年前
- 住所: 埼玉
- 連絡を取る:
Re: メモリリーク
ありがとうございます。重要なことですので、自分で調べてみようと思います。ISLe さんが書きました:解釈は概ね合ってます。spaaaark・∀・ さんが書きました:ありがとうございます。一応、「実体宣言は関数の終わりで解体され、newで生成したものはdeleteによって好きなタイミングで解体できる。」
と自分なりに解釈してみましたが、こんな感じでよろしいでしょうか。もちろん、解体忘れは論外として、です。
正確には関数ではなく『ブロック』が実体宣言に影響するのですが。
基本中の基本なので、自分なりではなく、規格書などの資料を調べてきちんとしっかり押さえておくべきかと思います。
『生存範囲(ライフサイクル)』は『可視範囲(スコープ)』に比べて解説記事での扱いが少ない印象を受けますけどね。
もちろんそれぞれ別物なので気を付けてください。
- spaaaark・∀・
- 記事: 66
- 登録日時: 12年前
- 住所: 埼玉
- 連絡を取る:
Re: メモリリーク
ありがとうございます。先の記事の調査結果を参考にしながら、こちらも使ってみようと思います。ISLe さんが書きました:ネイティブなポインタだとポインタが指すオブジェクトの面倒を見てくれませんが、スマートポインタは『スマートポインタ自身が解体されるとき』スマートポインタが指すオブジェクトを(必要ならば)解体します。spaaaark・∀・ さんが書きました:ありがとうございます。調べてみたところ、解体を忘れたインスタンス等をプログラム終了時に自動的に解体してくれるSTLのようですね。
解体忘れを自動的に修復してくれそうな機能です。気になる際に使用してみようと思います。
情報提供ありがとうございました><!
『スマートポインタ自身が解体されるとき』がキモです。
生存範囲(ライフサイクル)をきちんと理解せず誤った使い方をすると二重解体等の極めて発見しにくいバグを生むことになります。