VB6.0で開発しています。
以下のようなプログラムを書いた場合に
【2】では新しいインスタンスが作成されていると考えてよろしいですか?
私としては【2】をする前にNothingするべきではないかと
考えているのですが、
他の開発メンバーで以下のようなロジックを書く人がいます。
曖昧な説明では納得してもらえず、プログラムを直してもらえなくて困っております。
彼が言うには【2】の時点でクラスが初期化されているので
問題ないというのです。
この認識はあっているのでしょうか?
デバッグしてみても特に問題が起こっていませんので、
合っているような気もするのですが。。。
【2】の時点でどのようになっているか
教えて頂けませんか?
ぜひよろしくお願い致します。
Dim clsABC As clsMember 'Memberクラスがあると思って下さい。
'インスタンスの生成
clsABC = New clsMember
'-------------------
'いろいろな処理
'-------------------
'インスタンスの生成
【2】clsABC = New clsMember
'-------------------
'いろいろな処理2
'-------------------
Set clsABC = Nothing
※久々に答えられそうな内容なのでしゃしゃりでてきました
> 【2】では新しいインスタンスが作成されていると考えてよろしいですか?
はい.
> 彼が言うには【2】の時点でクラスが初期化されているので問題ないというのです。
> この認識はあっているのでしょうか?
何を問題と捉えているのか曖昧です…
「クラスが初期化」されるというのは,少し厳密に考えると「違う」という回答になります.
正しくは新しいclsMember型のインスタンスが作成され(ついでに初期化される)という感じです.
> 【2】の時点でどのようになっているか
最初の clsABC = New clsMember ではclsMember型のインスタンス(仮にinst_clsMemberと名付ける)が生成され,
clsABCにそのインスタンスへの参照が代入されます.
次の clsABC = New clsMember でも同様にclsMember型のインスタンスが生成され,
clsABCにそのインスタンスへの参照が代入されます.
このとき,元々clsABCに代入されていたinst_clsMemberはどこからも参照されなくなるため,
VBの内部でゴミ回収処理(GC)により破棄されます.
(確かVB6は参照カウント方式で管理していたと思うので,このGCはすぐさま行われるはずだと思います)
※最初の「いろいろな内容」で,inst_clsMemberに関係する,
他のインスタンスとで循環参照が起こっている時など,
GCがうまく働かない例があります.
# 既に回答が付いているけれどもしゃしゃり出てみたり。
> 以下のようなプログラムを書いた場合に
Set ステートメントが抜けているかも。
> 私としては【2】をする前にNothingするべきではないかと
> 考えているのですが、
基本的には不要です。
ライブラリ側でコレクション管理されている物(VB.Forms, DAO.Recordsets 等)などは
特定条件下においては、意図的に代入した方が良い場合もあるにはあるのですが、
少なくとも今回のような場合においては、無理に Nothing を代入する必要はありません。
とはいえ、そこで Nothing を代入したとて副作用があるわけでも無いので、
代入したとしても問題はありません。
> 彼が言うには【2】の時点でクラスが初期化されているので
> 問題ないというのです。
「初期化」の意図にもよりますが、次のインスタンスを再生成せねばならないなら、
現状のコードで問題無いでしょう。前のインスタンスの破棄は自動的に行われますので。
なお、最後の Nothing 代入も実際には不要です。それがモジュールレベル変数であるならば
オブジェクトの早期解放という意味を持ちますが、プロシージャレベルの変数の場合、
プロシージャから抜けるタイミングで、自動的に参照が破棄されるためです。
> 【2】の時点でどのようになっているか
> 教えて頂けませんか?
クラス側に以下のような処理を埋め込んでおき、ステップ実行してみると良いでしょう。
Private Sub Class_Initialize()
Debug.Print "==> 生成 "; TypeName(Me); " : "; ObjPtr(Me)
End Sub
Private Sub Class_Terminate()
Debug.Print "<== 破棄 "; TypeName(Me); " : "; ObjPtr(Me)
End Sub
ご回答ありがとうございました。
大変詳しい説明で理解できました。
プログラムでも確認しまして、
十分に理解できました。
インスタンス生成直後にGCが行われるのですね。
VB6.0でもガーベジコレクションが行われているとは
知りませんでした。
とても勉強になりました。
ありがとうございました。
> ガーベジコレクション
.NET の公式資料などでは、ガベージコレクションと訳されていますね。
# ガーベジ の方が元発音に近い気もしますが、国内では
# ガ(ー)ベージ と読まれることが多いようで。
以下蛇足:
ActiveX (COM) で使われるガベージコレクションのアルゴリズムは、
下記の「参照カウント」方式が採用されています。
http://ja.wikipedia.org/wiki/%E3%82%AC%E3%83%99%E3%83%BC%E3%82%B8%E3%82%B3%E3%83%AC%E3%82%AF%E3%82%B7%E3%83%A7%E3%83%B3
http://ja.wikipedia.org/wiki/%E5%8F%82%E7%85%A7%E3%82%AB%E3%82%A6%E3%83%B3%E3%83%88
ただし、 http://support.microsoft.com/kb/266088/ja にて
『VBScript は、JScript とは異なり、ガベージ コレクションを行う言語ではありません。』
と書かれるように、この参照カウント方式が、(言語機能としての)ガベージ コレクションとは
別物として扱われる可能性がある事に注意してください。
なお、ActiveX(COM)の参照カウント方式については、使用する言語が
VB/VBA/VBScript などであれば、言語側が面倒を見てくれるため、
今回のように破棄処理を省略することができますが、VB.NET/JScript などから
使った場合は、変数が破棄されても、ガベージコレクトが即座に発行されるわけでは
無いため、ActiveX オブジェクトの解放処理が遅れる可能性があります。
ガベージコレクションと使ったほうが良いのですね。
ありがとうございます。
補足説明もありがとうございました。
しっかり読んで理解しようと思います。
ツイート | ![]() |