みなさん、こんにちは。
作成したクラスを確実に解放するために、try~finally で括ると思いますが、
以下の場合、fooの中で例外が発生したら、インスタンス "List" が解放されません。
みなさんは、どの様にされていますか?
ご教授よろしくお願いします。
procedure TForm1.FormCreate(Sender: TObject);
var
List: TStrings;
i: Integer;
begin
try
List := TStringList.Create;
List.LoadFromFile('DATA.txt');
for i := 0 to List.Count - 1 do
begin
// 何らかの処理
foo(List.Strings[i]);
end;
finally
// finally節でメモリを確実に解放する
List.Free;
end;
end;
procedure TForm1.foo(Sender: String);
begin
raise Exception.Create('何らかのエラー');
end;
遊歩人
> 以下の場合、fooの中で例外が発生したら、インスタンス "List" が解放されませ
> ん。
D7では正常にfinallyにやってきます。List.Free;の後に
ShowMessage('finally'); と入れると表示されます。
遊歩人さんがfinallyにやってこないと判断された方法は
どのようなものでしょうか?
ありい
MLホームページ: http://www.freeml.com/delphi-users
----------------------------------------------------------------------
メンバーで使える掲示板を活用しよう!
http://ad.freeml.com/cgi-bin/sa.cgi?id=hHvLK
------------------------------------------------------[freeml byGMO]--
早々のリプライありがとうございます。
昔の「DEV CAMP」の資料を見ていて、「インスタンス "List" が解放されません」
というメモが残っていました。
メモリリークには、try~finallyを入れて気を付けていたので質問させて頂きまし
た。
遊歩人
遊歩人さん、こんにちは。
遊歩人さんがfinallyにやってこないと判断された方法は
どのようなものでしょうか?
ありい
MLホームページ: http://www.freeml.com/delphi-users
MLホームページ: http://www.freeml.com/delphi-users
----------------------------------------------------------------------
メールだけでみんなを招待できる便利機能♪
http://ad.freeml.com/cgi-bin/sa.cgi?id=hHwFB
------------------------------------------------------[freeml byGMO]--
そうですか...
実際に試されて問題がなければ、大丈夫だと思います。
というか私も同様の記述をしていますので、解放されて
ないと、かなり困ります(^^;
1点だけ、遊歩人さんが書かれた↓のコードですが、
> try
> List := TStringList.Create;
> List.LoadFromFile('DATA.txt');
(以下略)
以下のようにされることをお勧めします。
List := TStringList.Create; // tryの手前に引っ越す
try
List.LoadFromFile('DATA.txt');
万が一、TStringList.Createが失敗して例外を返した時
に、遊歩人さんのコードでは生成されていないListでFree
が走る可能性があります。
#今時はあまりないとは思いますが(^^; 強いて思いつく
#ケースを挙げるとメモリ不足とか...?
ちょっと気になりましたので書かせて頂きました m(__)m
ありい
MLホームページ: http://www.freeml.com/delphi-users
----------------------------------------------------------------------
練習や試合の予定調整は「とっとと決め太郎」におまかせ!
http://ad.freeml.com/cgi-bin/sa.cgi?id=hHwZb
------------------------------------------------------[freeml byGMO]--
遊歩人さん、ありいさん:
procedure TForm1.FormCreate(Sender: TObject);
var
List: TStrings;
i: Integer;
begin
try
List := TStringList.Create;
List.LoadFromFile('DATA.txt');
for i := 0 to List.Count - 1 do
begin
// 何らかの処理
foo(List.Strings[i]);
end;
finally
// finally節でメモリを確実に解放する
List.Free;
end;
end;
> 以下のようにされることをお勧めします。
>
> List := TStringList.Create; // tryの手前に引っ越す
> try
> List.LoadFromFile('DATA.txt');
>
> 万が一、TStringList.Createが失敗して例外を返した時
> に、遊歩人さんのコードでは生成されていないListでFree
> が走る可能性があります。
>
> #今時はあまりないとは思いますが(^^; 強いて思いつく
> #ケースを挙げるとメモリ不足とか...?
ありいさんのおっしゃるように、コンストラクタが失敗する
ケースもありますので、次のどちらかにすることをお勧めします。
List:=TStringList.Create;
try
<いろいろな処理>
finally
List.Free;
end;
List:=nil;
try
List:=TStringList.Create;
<いろいろな処理>
finally
List.Free;
end;
ちなみに私は後者が好きです。 後者であれば(コンストラクタが
失敗する可能性のある)変数が複数になっても同じスタイルで
いけるからです。
List1:=nil;
List2:=nil;
try
List1:=TStringList.Create;
List2:=TStringList.Create;
<いろいろな処理>
finally
List1.Free;
List2.Free;
end;
GetMem などのリソース確保も、同じように実装すると統一感があって
いいですね。
Ptr:=nil;
try
GetMem(Ptr,1024);
<いろいろな処理>
finally
FreeMem(Ptr);
end;
余談ですが、上記のようなことを考えると、デストラクタは
「コンストラクタがどこでエラーになっても、問題を出さない
ように作らないといけない」ことがわかります。 ライブラリの
終了処理なども同様です。
――――――――――――――――――――――――――――――――――――
株式会社イマジオム 代表取締役 高木太郎
〒316-0024 茨城県 日立市 水木町 1-11-10
電話:0294-28-0147
ファクシミリ:0294-28-0148
電子メール:tarou_...@imageom.co.jp
ホームページ:http://www.imageom.co.jp/
MLホームページ: http://www.freeml.com/delphi-users
----------------------------------------------------------------------
毎日豪華プレゼントキャンペーン開催中!くまポン
http://ad.freeml.com/cgi-bin/sa.cgi?id=hHxxN
------------------------------------------------------[freeml byGMO]--
> List1:=nil;
> List2:=nil;
> try
> List1:=TStringList.Create;
> List2:=TStringList.Create;
> <いろいろな処理>
> finally
> List1.Free;
> List2.Free;
> end;
な・る・ほ・ど~☆
高木さんのソースを見て、やっっっとヘルプ(D7)のFreeの
言ってる意味が理解できました(^^;
(D7ヘルプより引用)
> オブジェクトが nil の場合でも Free メソッドはエラーにはなりません。
> このため,オブジェクトが初期化されていない場合に Free メソッドを呼び出してもエラーにはなりません。
List2のCreateで失敗しても確実にList1を破棄して、List2
はスルーしてくれるんですね!
nilのFreeが呼べることを知ってはいたのですが、感覚的に
とても気持ち悪くて今まで使用を避けていたのですが、おかげ
さまで大分すっきりしました。
#nil.Freeって思うと、やっぱり完全には払拭できませんが(^^;
#一種のシンタックスシュガーと思い込もうと思えば思えなく
#もないというか...(^^;
...考え中...
...今後、高木派に改宗しますっ!
大変勉強になりました。ありがとうございました m(__)m
ありい
MLホームページ: http://www.freeml.com/delphi-users
----------------------------------------------------------------------
使い方はいろいろ♪一部のメンバーだけにMLメールを送ろう!
http://ad.freeml.com/cgi-bin/sa.cgi?id=hHxJT
------------------------------------------------------[freeml byGMO]--
細川です。
> #nil.Freeって思うと、やっぱり完全には払拭できませんが(^^;
> #一種のシンタックスシュガーと思い込もうと思えば思えなく
> #もないというか...(^^;
nil.Free っていう訳では無いのです。
TMethod ヘルプとかをみると判りますがメソッドポインタというのは2つに別れ
ています。
コードへのポインタと、インスタンスごとのデータへのポインタです。
TMethod でいうと
TMethod.Code
TMethod.Data
です。
それぞれポインタになっています。
Free のコードを見ると Self が nil かどうかを調べています。
これはインスタンスごとのデータが nil なのかどうか、ということで、コード
自体は存在しているのです。
よろしくお願いします。
Regards,
HOSOKAWA Jun
[S/G] SERIALGAMES Inc.
TEL: 03-5812-0980
FAX: 03-5812-0970
twitter: http://twitter.com/serialgames
twitter: http://twitter.com/flaver_sg
mailto: j...@serialgames.co.jp
fla:ver http://flaver.jp/
WebCapS http://www.serialgames.co.jp/fun.html#WebCapSeria
MLホームページ: http://www.freeml.com/delphi-users
----------------------------------------------------------------------
メンバーで使える掲示板を活用しよう!
http://ad.freeml.com/cgi-bin/sa.cgi?id=hHxTy
------------------------------------------------------[freeml byGMO]--
> nil.Free っていう訳では無いのです。
(略)
> Free のコードを見ると Self が nil かどうかを調べています。
> これはインスタンスごとのデータが nil なのかどうか、ということで、コード
> 自体は存在しているのです。
はい。こちらも「感覚的に」そうかなぁ~と思っていました。
nil.Freeはコードを見た時に、例えばJavaなら「ぬるぽ」だろ
的な気持ち悪さを表現しました。
Freeの実装で、Selfがnilかを調べていてnilでない場合には
Destroyを呼んでいるのは判ったのですが、そもそもどうやって
obj(中身nil)がTObject.Freeに辿りつくことができるのかが、
謎だな~と思うのです。
#今までの気持ち悪さの主因です。
obj(中身nil)がFree以外のメソッドを呼んだらアドレス違反に
なりますよね?
#Freeの場合はDelphi内部で宜しく取り計らってくれているんだ
#ろう、程度の認識です。これをシンタックスシュガーと表現し
#ました。
そして細川さんの解説の、
> TMethod ヘルプとかをみると判りますがメソッドポインタというのは2つに別れ
> ています。
> コードへのポインタと、インスタンスごとのデータへのポインタです。
> TMethod でいうと
>
> TMethod.Code
> TMethod.Data
>
> です。
> それぞれポインタになっています。
...という部分を拝見して、インスタンスが見つからない(objが
nilの)場合に、Freeに限りTObject.Freeのコードに流れる細工が
あるのかなぁ、と推測している次第です。
...外していますでしょうか?(^^;
また、今となっては難しいかもしれませんが、Delphiの内部的
な動きを解説している書籍などで良い本がありましたら紹介して
頂けないでしょうか(日本語で...) m(__)m
解説して頂いた上にお願いで恐縮ですが...
よろしくお願いします m(__)m
ありい
MLホームページ: http://www.freeml.com/delphi-users
----------------------------------------------------------------------
メールだけでみんなを招待できる便利機能♪
http://ad.freeml.com/cgi-bin/sa.cgi?id=hH05F
------------------------------------------------------[freeml byGMO]--
ありいさん:
> nil.Freeはコードを見た時に、例えばJavaなら「ぬるぽ」だろ的な
> 気持ち悪さを表現しました。
>
> Freeの実装で、Selfがnilかを調べていてnilでない場合には
> Destroyを呼んでいるのは判ったのですが、そもそもどうやって
> obj(中身nil)がTObject.Freeに辿りつくことができるのかが、
> 謎だな~と思うのです。
>
> obj(中身nil)がFree以外のメソッドを呼んだらアドレス違反に
> なりますよね?
お気持ちは非常にわかりますが、実際にはちょっと違います。 試しに
下記のコードを試してみてください。
{$APPTYPE CONSOLE}
type TSomething=
class(TObject)
procedure WriteMessage;
end;
type TMainForm=
class(TForm)
Button:TButton;
procedure ButtonClick(Sender:TObject);
end;
procedure TSomething.WriteMessage;
begin
WriteLn('Hello!');
end;
procedure TMainForm.ButtonClick;
var Something:TSomething;
begin
Something:=nil;
Something.WriteMessage;
end;
ボタンを押すと、Something.WriteLog でアクセス違反が生じるかと
思われるでしょうが、実際にはコンソール画面に Hello! と表示
されます。
なぜかと言うと、コンパイラは Something が TSomething であると
いうことをしっかり理解していて、Something.WriteMessage 文を
TSomething.WriteMessage メソッドの呼び出しに置き換えてくれる
からです。 WriteMessage メソッドでは、Something インスタンスを
まったく使っていないので、(この例のように)たとえインスタンスが
存在していなくても問題なく動作します。 つまり──
1.メソッドの呼び出し(エントリアドレスの取得)だけなら、
インスタンスの存在は必須ではない。
2.未作成オブジェクトや破棄済みオブジェクトのメソッドを
呼び出してアクセス違反が生じるのは、そのメソッドが
何らかの形でインスタンスを使っているから。
──ということになります。
メソッドのエントリアドレスは、コンパイルされる時点ですべて
決めることができます。 したがって実行時に、エントリアドレスが
見つからないという理由でアクセス違反が起きることは、通常は
(DLLでも使っていなければ)ありません。
アクセス違反が起きるのは「メソッドがインスタンスの存在を前提と
した作りになっているのに、実際にはインスタンスが存在していない」
場合です。 Free の場合には、インスタンスの存在を前提として
いない(インスタンスへのポインタが nil かどうか事前にチェック
している)ので、問題が起きないというわけです。 特にコンパイラが
Free を特別扱いしているわけではありません。
――――――――――――――――――――――――――――――――――――
株式会社イマジオム 代表取締役 高木太郎
〒316-0024 茨城県 日立市 水木町 1-11-10
電話:0294-28-0147
ファクシミリ:0294-28-0148
電子メール:tarou_...@imageom.co.jp
ホームページ:http://www.imageom.co.jp/
MLホームページ: http://www.freeml.com/delphi-users
----------------------------------------------------------------------
練習や試合の予定調整は「とっとと決め太郎」におまかせ!
http://ad.freeml.com/cgi-bin/sa.cgi?id=hH2Jn
------------------------------------------------------[freeml byGMO]--
> なぜかと言うと、コンパイラは Something が TSomething であると
> いうことをしっかり理解していて、Something.WriteMessage 文を
> TSomething.WriteMessage メソッドの呼び出しに置き換えてくれる
> からです。 WriteMessage メソッドでは、Something インスタンスを
> まったく使っていないので、(この例のように)たとえインスタンスが
> 存在していなくても問題なく動作します。 つまり──
>
> 1.メソッドの呼び出し(エントリアドレスの取得)だけなら、
> インスタンスの存在は必須ではない。
>
> 2.未作成オブジェクトや破棄済みオブジェクトのメソッドを
> 呼び出してアクセス違反が生じるのは、そのメソッドが
> 何らかの形でインスタンスを使っているから。
実際に試してみました!
SomethingがTSomethingであるということは型指定から自明なので、
「全ての」メソッド呼び出しで、
1)自クラス(インスタンスでない)のメソッドに辿りついて実行
→細川さん解説の「TMethod...コードへのポインタと、インスタンス
ごとのデータへのポインタです。」の部分ですね!
2)実行して、作ってもいない自分のフィールドにアクセスすると
アドレス違反が発生する
※多態とかは考えていません。ざっくりとしたイメージです。
極端なことを言うと、VCL含めて「全ての」メソッド呼び出しの頭
にif Self = nil then exit; と入れておけば、生成漏れによるアド
レス違反のない世界が構築できるって事ですね!
#プロパティやフィールドも全てSetter/Getter作って同じつくりに
#すれば(^^;
##他にも穴があるかもしれませんが...(^^;;;
> Free の場合には、インスタンスの存在を前提として
> いない(インスタンスへのポインタが nil かどうか事前にチェック
> している)ので、問題が起きないというわけです。 特にコンパイラが
> Free を特別扱いしているわけではありません。
上記を含めて、とても納得することができました。
#それはそれとして「インスタンスは作って操作、しっかり解放」が
#キホン、なのは肝に銘じるべきですね!
高木さん、細川さん、ありがとうございました m(__)m おかげさま
で新年をすっきり気持ちよく迎えられそうです(^^)
遊歩人さんも、きっかけを下さりありがとうございました m(__)m
ありい
MLホームページ: http://www.freeml.com/delphi-users
----------------------------------------------------------------------
毎日豪華プレゼントキャンペーン開催中!くまポン
http://ad.freeml.com/cgi-bin/sa.cgi?id=hH9eK
------------------------------------------------------[freeml byGMO]--
高木さんの解説はいつも本当に目から鱗です。
これらの処理を行っているのは Delphi のコンパイラです。
コンパイラの立場に立てば至極当たり前の事ですが、中々
理解するのが難しいです。
大変参考になりました。
これからもよろしくお願いいたします。
--
Atsushi Matsuno / HEXARD INC.
E-mail: mat...@hexard.co.jp
MLホームページ: http://www.freeml.com/delphi-users
----------------------------------------------------------------------
使い方はいろいろ♪一部のメンバーだけにMLメールを送ろう!
http://ad.freeml.com/cgi-bin/sa.cgi?id=hH9kL
------------------------------------------------------[freeml byGMO]--