コレクションにAddしたオブジェクトの破棄方法

解決


だん  2007-03-28 11:47:47  No: 135922

コレクションにAddしたオブジェクトの破棄方法
を教えていただけますでしょうか。

現状は、下記のようにしています。
    Do While myCollection.Count <> 0
        Call myCollection.Remove(1)
    Loop
    Set myCollection = Nothing

また、VBでは、変数がスコープ外になった場合、
オブジェクトは自動で破棄されると聞いた事があります。
確証は得てません。

オブジェクトの破棄方法について、
確証をとれる、MSDNのURLなどありましたら、
お教え下さい。

以上、よろしくお願いいたします。


特攻隊長まるるう  2007-03-28 17:27:48  No: 135923

VBのバージョンにも、対象のオブジェクトにも依存して、
必要な手順が変わります。

コレクションから Remove しても、それはコレクションが
参照しなくなるというだけで、格納されていたオブジェクトの
終了処理が正しく行われる保障はありません。

Set って書いてるから[VB6.0]だと仮定します。
…が、もはや、WEB上で検索しても引っ掛からなくなったので、
ローカルのヘルプを読んでください。

> また、VBでは、変数がスコープ外になった場合、
> オブジェクトは自動で破棄されると聞いた事があります。
> 確証は得てません。
『有効期間』というキーワードでヘルプを検索してみてください。
『静的変数』というページとか。。。
[MSDN ライブラリ Visual Studio 6.0]
└[Visual Basic ドキュメント]
  └[Visual Basic の使用方法]
    └[プログラミング ガイド]
      └[Visual Basic の基本]
        └[プログラミングの基礎]
          └[変数、定数、およびデータ型]
            └[静的変数]
スコープの話もこの近辺に書いてあります。

ただ、単純な値型の変数ではなく、オブジェクトを
対象とする場合、そのオブジェクトが終了処理の実行を
必要とする場合があります。

例えばデータベースの接続(コネクション)だと、Close
しないで Open し続けると上限に達し、接続できなくなります。
Nothing の設定は実行しても意味ありません。

ファイルを開く時も似たようなことが起こったと思います。
http://www.microsoft.com/japan/msdn/vbasic/migration/tips/using/

Form だと
http://madia.world.coocan.jp/vb/vb_bbs/200606_06060073.html
とか。。。

[VB.NET]になってくるとCOMの解放も重要になってきます。
http://msdn.microsoft.com/library/ja/cpguide/html/cpconDeveloperBackgroundsInMemoryManagement.asp
http://jeanne.wankuma.com/tips/programing/releasecom.html

いずれにしろ、
対象となるオブジェクトの仕様を理解し、
正しい(必要な)終了処理を実行してから、
Nothing を設定して参照を解除する必要があると思います。

Nothing の設定は、対象のオブジェクトへ『参照しないよ』
と伝えるだけで、オブジェクトの破棄に関しては、そのオブジェクト
に対する知識が必要だと理解してください。


だん  2007-03-29 09:33:41  No: 135924

環境を書き忘れました。
VB6です。

それでは、Removeの前に、
アイテムを取得し、nothingをSet(オブジェクトの解放)
をする。ということでしょうか。

<例>
    Do While myCollection.Count <> 0
        Set abc = myCollection.Item(1)
        Set abc = nothing
        Call myCollection.Remove(1)
    Loop
    Set myCollection = Nothing
こんな感じですかね。

スコープについては、読んでみた後、
理解できないようであれば、別スレッドで、
再度質問させていただこうと思います。


K.J.K.  2007-03-29 10:19:15  No: 135925

COMオブジェクトで参照カウントが正しく用いられているでしょうから、
Set myCollection = Nothing
だけで、十分です。


特攻隊長まるるう  2007-03-29 11:10:33  No: 135926

> COMオブジェクトで参照カウントが正しく用いられているでしょうから
そうですね。一般的なものなら。。。

コレクションは何でも入るから、自作のクラスも
格納するだろうし。。。と少しレベルの高い内容に
踏み込みましたが、むしろ格納される側のオブジェクトの
設計の話なので、質問の趣旨と外れますかね?

> こんな感じですかね。
考え方としては合ってるけど、実際に実行するのが
Nothing の設定だけでいいなら Remove するだけで
いいと思います。
K.J.K.さんのご指摘通りです。

繰り返しますが、
Nothing の設定・・・参照の解放
オブジェクトの破棄・・・終了処理が必要な場合がある
です。両者は関係ありますが、同一ではありません。
例えば

[VB6.0]実行する前に C:\test.txt を作成してください
'/// Form1
Option Explicit

Private m_Collection As New Collection
Private m_Count As Integer

Private Sub Form_Load()
    Me.Command1.Caption = "Add"
    Me.Command2.Caption = "Remove"
End Sub

Private Sub Command1_Click()
    Dim cs1 As New Class1
    cs1.Name = "Class1_" & CStr(m_Count)
    Call cs1.FileOpen '開くだけで閉じない
    m_Count = m_Count + 1
    m_Collection.Add cs1
End Sub

Private Sub Command2_Click()
    Dim cs1 As Class1
    Do While m_Collection.Count <> 0
        Call m_Collection.Remove(1)
        '↓変更すれば Add → Remove → Add できる
'        Set cs1 = m_Collection.Item(1)
'        Call cs1.FileClose
'        Call m_Collection.Remove(1)
    Loop
    Set m_Collection = Nothing
End Sub

'/// Class1
Option Explicit

Public Name As String
Public FileNo As Integer

Private Sub Class_Initialize()
    Debug.Print CStr(Now) & " Class_Initialize"
End Sub

Private Sub Class_Terminate()
    Debug.Print CStr(Now) & " Class_Terminate " & Me.Name
End Sub

Public Sub FileOpen()
    FileNo = 1 'FreeFile を使うと新しい番号が取得され、
                '問題が表面化しないがファイルは開きっぱなし
    Open "C:\test.txt" For Input As #FileNo
    
'    Close #FileNo 'Close を実行しないと閉じない
End Sub

Public Sub FileClose()
    Close #FileNo
End Sub

このようなサンプルプログラムがあったとします。
このまま、Add 2回でエラーになるのは FreeFile
でファイル番号を取得してないからですが、
Add → Remove → Add でエラーになるのは
なぜでしょうか?

クラスは破棄されていますが、ファイル番号が
使われたままだからです。破棄する前に FileClose
を呼ぶ必要がある例です。

もしくは、Class_Terminate で FileClose を
呼ぶような設計もあります。しかし、そうなると
FileOpen しないで破棄したときの検証も必要と
なります。

Class1 がどんな設計か?知らないと、使用した
全てのメモリを回収できないですよね?
そんな知識をつけて頂きたかったのです。


特攻隊長まるるう  2007-03-29 13:07:54  No: 135927

理解が不十分でした。
K.J.K.さんの指摘は
コレクションごと破棄するなら Do 〜  Loop
さえ要らないって事ですね。

ボクのサンプルプログラムでなら FileOpen の処理を
削除して、Do 〜  Loop の Remove の処理も削除して
ください。

複数個 Add して
    Set myCollection = Nothing
の実行だけで

2007/03/29 13:06:30 Class_Terminate Class1_0
2007/03/29 13:06:30 Class_Terminate Class1_1
2007/03/29 13:06:30 Class_Terminate Class1_2
と出力されますよね?
クラスの破棄は全て実行されていますね?


だん  2007-03-30 10:48:41  No: 135928

ありがとうございました。

Set myCollection = Nothing
とします。


※作成する前に利用規約をご確認ください。

※Google reCAPTCHA認証からCloudflare Turnstile認証へ変更しました。







   このエントリーをはてなブックマークに追加