(for Internet Explorer)
← ▼ ▲
↑
new_ObjectsFromStream
(src)
Sub new_ObjectsFromStream( out_Objs as array of object, ClassName as string, Stream as variant )
ストリームから、オブジェクトをいくつか生成して、配列に格納します。
【引数】
out_Objs
ClassName
（出力） ストリームから生成したオブジェクトが入った配列
生成するオブジェクトのクラス名
Stream
XML ストリーム
１つもオブジェクトを生成しなかったときでも、out_Objs には配列が格納されます。
ClassName, Stream については、
→ new_ObjectFromStream
テスト
→ T_ObjectFromStream フォルダ
← ▼ ▲
NameOnlyClass
Class NameOnlyClass
Public Name
Public Delegate
End Class
Name 変数（任意の型の識別値）と、Delegate 変数（指しているオブジェクトなど）の
対応関係を表すクラスです。
Delegate 変数を使わずに、Name だけのオブジェクトとして使うこともできます。
(src)
→ ArrayToNameOnlyClassArray
関連
→ JoinedClass
xml プロパティ
に対応しています。
← ▼ ▲
new_NameOnlyClass
Function new_NameOnlyClass( in_Name as string, in_Delegate as variant ) as NameOnlyClass
NameOnlyClass のオブジェクトを生成します。
(src)
← ▼ ▲
JoinedClass
Class JoinedClass
Public Left
Public Right
End Class
(src)
→ ArrayClass
配列番号 0 と 1 で対応関係を表すことができます
→ PointerPairClass (clib)
関連
Left 変数の値と Right 変数の値の対応関係を表すクラスです。
→ NameOnlyClass
→ pair - cpprefjp - C++ Library Reference (Web)
← ▼ ▲
new_JoinedClass
Function new_JoinedClass( Left as variant, Right as variant ) as JoinedClass
JoinedClass のオブジェクトを生成します。
【引数】
Left
Right
生成するオブジェクトの Left プロパティに設定する値
生成するオブジェクトの Right プロパティに設定する値
返り値
生成された JoinedClass のオブジェクト
ソース
→ vbslib.vbs
→ JoinedClass
← ▼ ▲
g_ObjectIDs
オブジェクトに数値の ID を割り当て、ID からオブジェクトが取得できるようにします。
Set root = new SampleRootClass
Set element = new SampleElementClass
'// Link
element.RootObjectID = root.ObjectID
Set root.Element = element
'// Call a method
element.Method
Class SampleRootClass
Public ObjectID
Public Element
Private Sub Class_Initialize()
Me.ObjectID = g_ObjectIDs.Add( Me )
End Sub
Private Sub Class_Terminate()
g_ObjectIDs.Remove Me.ObjectID
End Sub
End Class
Class SampleElementClass
Public RootObjectID
Public Sub Method()
Set root = g_ObjectIDs( Me.RootObjectID )
End Sub
End Class
サンプル
相互参照しているときの Class_Terminate
が期待通りに動作するようになります。
SampleRootClass
SampleElementClass
Element メンバー
RootObjectID メンバー （g_ObjectIDs 経由）
g_ObjectIDs
g_ObjectIDs
g_ObjectIDs
→ vbslib.vbs
ソース
.Add
.Remove
.Item
新規 ID を取得します
ID を返却します
Add できる最大数、同時に存在できる ID の数は 0x7FFE です。
同時に存在できる ID の数を超えて、Remove と Add を繰り返すと、返却された ID を再利用します。
同じオブジェクトに複数の ID が割り当てられる状況になっても、エラーにはなりません。
渡された ID に対応するオブジェクトを返します
→ ObjectSetClass
関連
← ▼ ▲
LifeGroupClass
相互参照しているオブジェクトに対して、適切に
所属オブジェクト（ルート以外）
所属オブジェクト（ルート）
LifeGroup
ハンドル（ルート以外へ） as LifeHandleClass
p
p
ハンドル（ルートへ）
→ グループのルートの生成
→ グループのメンバーの生成
DestroyReferences
ユーザーの変数
ユーザーの変数
所属オブジェクトのメンバー変数やメソッドにアクセスするときは、ハンドルのメンバー変数 p を
介する必要があります。
相互参照
関連
→ 相互参照しているときの Class_Terminate
→ ガーベージコレクション (GC)
参考
一般に、関数が終了したときにオブジェクトを参照している変数がなくなると、ガーベージコレクター
(1)
(2)
(3)
(4)
(5)
(7)
(6)
内部で相互参照するグループに LifeGroupClass を使うと下記の図のような構成になります。
グループに所属しているオブジェクトの Class_Terminate が呼び出されるタイミングは、
グループに所属しているオブジェクト（ルート オブジェクトも含む）を参照するすべてのハンドルが、
すべてのユーザーの変数から参照されなくなったときです。
( ) の中の数字は、削除される順番です。
(1) と (3)、(2) と (4)、(5) と (7) の順番は入れ替わることがあります。
(1) だけが削除されたときは、(3)が削除されるまで、(4)以降のオブジェクトは残ります。
によって
プログラム終了時に呼ばれます。 LifeGroupClass は、相互参照しているオブジェクトでも
Class_Terminate が呼び出されるようにします。
が呼ばれますが、相互参照していると Class_Terminate は呼ばれません。
Class_Terminate
このように相互参照しているオブジェクトとハンドルのオブジェクトを分けることで、
参照している変数がなくなったことをハンドルで検出できるようにしています。
オブジェクト ID を経由することで Class_Terminate を呼び出す
A
B
相互参照
→ T_Dic.vbs
T_LifeGroupClass
→ vbslib.vbs
テスト
ソース
注意
メンバー変数やメソッドにアクセスするときは、メンバー変数 p を介する必要があります。
→ グループのルートの使用サンプル
辞書
のキーや配列番号で参照することで、相互参照が原因で Class_Terminate が呼ばれなく
なる状況を回避することができます。
root.p.Member
辞書のキーや配列番号
B
A
オブジェクトの Set
Class_Terminate
が呼ばれるようにします。
→ g_ObjectIDs
p を介する必要がないが、多少手間がかかるライフサイクル管理
→ DestroyerClass
→ g_ObjectIDs
← ▼ ▲
グループのルートの生成 （LifeGroupClass）
Class RootClass
Public p '// as RootBodyClass : Target object of this handle
Private Sub Class_Initialize()
Set group = new LifeGroupClass
group.AddHandle Me, new RootBodyClass
End Sub
Private Sub Class_Terminate()
If not IsEmpty( Me.p.LifeGroup.Group ) Then _
Me.p.LifeGroup.Group.AddTerminated Me.p
End Sub
End Class
使用サンプル
RootBodyClass
相互参照しているオブジェクトのグループのうち、最初に生成するオブジェクトのハンドルの
クラスは、下記のように定義します。 RootBodyClass を最初に生成するオブジェクトのクラス名
に変更すること以外は、そのままにしてください。
Class RootBodyClass
:
Public LifeGroup '// Don't write except for LifeGroupClass ■追加
Public Sub DestroyReferences() '// ■追加
Me.Reference = Empty
End Sub
End Class
最初に生成するオブジェクトのクラスは、メンバー変数 LifeGroup と、
DestroyReferences メソッド
を定義してください。
LifeHandleClass
定義サンプル
Set root = new RootClass
root.p.Member
と同じメンバーを持ちます。
<< LifeGroupClass
グループのルート（下記の RootClass）は、
RootClass
RootBodyClass
Reference
p
メンバー変数やメソッドにアクセスするときは、メンバー変数 p を介する必要があります。
… p の追加が必要
相互参照しているオブジェクトを使用するコードに、この変更を要求することがどうしても
できないなら、p を介すだけのメソッドやプロパティを定義します。
DestroyReferences
LifeGroupClass
AddHandle
← ▼ ▲
グループに所属するオブジェクトの生成 （LifeGroupClass）
相互参照しているオブジェクトのグループに所属するオブジェクトのメソッドから、グループに
所属させるオブジェクトを新しく生成するときは、下記の CreateMember メソッドのように、
グループに追加します。 そうしなければ、グループが削除されるタイミングで、生成した
オブジェクトに対して DestroyReferences が呼ばれなくなります。
Class RootBodyClass
:
Public LifeGroup '// Don't write except for LifeGroupClass
Function CreateMember()
Set CreateMember = Me.LifeGroup.Group.Add( new MemberClass )
:
End Function
End Class
定義サンプル
MemberClass
Class MemberClass
:
Public LifeGroup '// Don't write except for LifeGroupClass ■追加
Public Sub DestroyReferences() '// ■追加
Me.Reference = Empty
End Sub
End Class
グループに所属するオブジェクトのクラスは、メンバー変数 LifeGroup と、
定義サンプル
DestroyReferences メソッド
を定義してください。
LifeHandleClass
です。
CreateMember メソッドの返り値は、
使用サンプル
Set root = new RootClass
Set member = root.p.CreateMember()
<< LifeGroupClass
MemberClass
Add
すぐに CreateMember の返り値を参照しなくなっても、DestroyReferences がすぐに呼ば
れることはありません。 グループに所属するすべてのオブジェクトが参照されなくなった
ときに呼び出されます。
ルートのハンドルが参照されなくなったときに、グループに所属する一部のオブジェクトが
削除されても構わないときは、ハンドルの代わりに生成したオブジェクトを返しても構いま
せん。
← ▼ ▲
グループに所属するオブジェクトの出力 （LifeGroupClass）
相互参照しているオブジェクトを出力するときは、下記の SearchMember メソッドのように、
LifeHandleClass
を生成して返してください。
Class RootBodyClass
:
Public LifeGroup '// Don't write except for LifeGroupClass
Function GetReference()
Set GetReference = Me.LifeGroup.Group.Add( Me.Reference )
End Function
End Class
定義サンプル
使用サンプル
Set root = new RootClass
Set member = root.p.GetReference()
Add (LifeGroupClass)
を呼び出し、
GetReference
ただし、グループの中で参照するときは、LifeHandleClass を生成しないでください。
そうしなければ、ルートのハンドルが削除されるタイミングで、グループに所属する一部の
オブジェクトが削除されてしまいます。 ルートのハンドルが参照されなくなったら、グループ
に所属する一部のオブジェクトが削除されても構わないときは、LifeHandleClass を生成
しなくても構いません。
← ▼ ▲
DestroyReferences メソッド
Sub （グループのに所属するオブジェクトのクラス）::DestroyReferences()
相互参照を切ります。
グループのユーザーは、本メソッドを直接呼び出さないでください。
Class_Terminate メソッド（デストラクター）が呼び出されて、オブジェクトが
破棄されるように、相互参照を切ってください。 つまり、相互に参照している
関係にあるメンバー変数に Empty や Nothing を代入してください。
<< LifeGroupClass
AddTerminated (LifeGroupClass)
から呼ばれます。
Class RootBodyClass
:
Function DestroyReferences()
Me.Member = Empty
End Function
End Class
定義サンプル
← ▼ ▲
LifeHandleClass
LifeGroupClass
（グループ）に所属する、相互参照しているオブジェクトを参照できるハンドル。
LifeHandleClass が参照している、相互参照しているオブジェクトを、グループの外にある変数
に直接格納しないでください。 もしそうしてしまうと、すべてのハンドルへの参照が無くなったときに、
相互参照が切れたオブジェクトになり、正しく動作しなくなります。
→ p
メンバー
→ Class_Terminate
生成
→ グループのルートの生成
→ グループのメンバーの生成
相互参照しているオブジェクトを参照します。
AddTerminated (LifeGroupClass)
を呼び出します。
<< LifeGroupClass
オブジェクトのメンバー変数やメソッドにアクセスするときは、メンバー変数 p を介する必要が
あります。
Set root = new RootClass
Set member = root.p.CreateMember() '// member as LifeHandleClass
member.p.Method
サンプル
← ▼ ▲
p (LifeHandleClass)
Dim LifeHandleClass::p as Object
グループに所属している相互参照しているオブジェクトを参照します。
<< LifeHandleClass
→ LifeGroupClass
参考
オブジェクトのメンバー変数やメソッドにアクセスするときは、ハンドルのメンバー変数 p を
介する必要があります。 このように相互参照しているオブジェクトとハンドルのオブジェクトを
分けることで、参照している変数がなくなったことをハンドルで検出できるようにしています。
← ▼ ▲
Class_Terminate (LifeHandleClass)
Sub LifeHandleClass::Class_Terminate()
ハンドルが参照されなくなったときに、
<< LifeHandleClass
AddTerminated (LifeGroupClass)
を呼び出します。
← ▼ ▲
LifeGroupClass のメンバー
→ AddHandle
→ Add
→ Remove
→ AddTerminated
オブジェクトをグループに追加し、ハンドルからオブジェクトを参照できるようにします
オブジェクトをグループに追加して、そのオブジェクトを参照するハンドルを生成します
オブジェクトをグループから除外します
ハンドルから参照されるカウンターを減らし、必要なら相互参照を切ります
<< LifeGroupClass
← ▼ ▲
AddHandle (LifeGroupClass)
Sub LifeGroupClass::AddHandle( Handle as Object, Object as Object )
オブジェクトをグループに追加し、ハンドルからオブジェクトを参照できるようにします。
【引数】
Handle
（ルートの）ハンドル
ハンドルが参照しようとしているオブジェクト
Object
<< LifeGroupClass のメンバー
← ▼ ▲
Add (LifeGroupClass)
Function LifeGroupClass::Add( Object as Object ) as LifeHandleClass
オブジェクトをグループに追加して、そのオブジェクトを参照するハンドルを生成して返します。
【引数】
Object
ハンドルが参照しようとしているオブジェクト
返り値
生成されたハンドル
<< LifeGroupClass のメンバー
← ▼ ▲
Remove (LifeGroupClass)
Sub LifeGroupClass::Remove( Object as Object )
オブジェクトをグループから除外します。
【引数】
Object
ハンドルが参照しているオブジェクト
<< LifeGroupClass のメンバー
← ▼ ▲
AddTerminated (LifeGroupClass)
Sub LifeGroupClass::AddTerminated( Object as Object )
ハンドルから参照されるカウンターを減らし、必要なら相互参照を切ります。
【引数】
Object
参照されなくなったハンドルが参照しているオブジェクト
相互参照を切ることで、グループに所属するすべてのオブジェクトが削除されます。
自分（Me）も削除されます。
グループに所属するオブジェクトを参照するハンドルが他にもあるときは、
Object を参照しているハンドルだけが削除され、Object は残ります。
→ LifeGroupClass
参考
<< LifeGroupClass のメンバー
グループのユーザーは、本メソッドを直接呼び出さないでください。
から呼ばれます。
LifeHandleClass
の
Class_Terminate
← ▼ ▲
DestroyerClass
→ T_Dic.vbs
T_DestroyerClass
→ vbslib.vbs
テスト
ソース
相互参照しているオブジェクトを削除するタイミングを制御するオブジェクト。
DestroyerClass のオブジェクトが削除されるときに、相互参照を切るメソッド DestroyReferences
を呼び出し、相互参照していたオブジェクトの Class_Terminate が呼び出されます。
Case1
WScript.echo "End of Main"
Case2
WScript.echo "End of Main"
WScript.echo "もし、ここ以降でデストラクターが動くときは、"+_
"プログラム終了時にすべてのオブジェクトを削除する"+_
"ことによるデストラクター呼び出しです。"
Sub Case1()
WScript.echo vbCRLF +"Case1:"
Set destroyer = new DestroyerClass
Set a_object = new MutualClass : a_object.Name = "a" : destroyer.Add a_object
Set b_object = new MutualClass : b_object.Name = "b" : destroyer.Add b_object
Set a_object.Reference = b_object
Set b_object.Reference = a_object
End Sub
Sub Case2()
WScript.echo vbCRLF +"Case2:"
Set destroyer = new DestroyerClass
Set a_object = new MutualClass : a_object.Name = "a"
Set b_object = new MutualClass : b_object.Name = "b"
Set a_object.Reference = b_object
Set b_object.Reference = a_object
End Sub
Class MutualClass
Public Name
Public Reference
Public IsDestroyer '// ■追加
Private Sub Class_Terminate()
WScript.echo Me.Name +".Class_Terminate"
CheckUnderDestroyer Me '// ■追加
End Sub
Public Sub DestroyReferences() '// ■追加
Me.Reference = Empty
End Sub
End Class
サンプル
Destroyer
A
B
相互参照を切る
関数が終了したときにオブジェクトを参照している変数がなくなると、ガーベージコレクターによって
Class_Terminate が呼ばれますが、相互参照していると Class_Terminate は呼ばれません。
プログラム終了時に呼ばれます。 DestroyerClass は、相互参照しているオブジェクトでも
Class_Terminate が呼ばれるようにします。
相互参照するクラスは、相互参照を切る DestroyReferences メソッドと、DestroyerClass に
登録されると True になる IsDestroyer 属性（プロパティ）を実装してください。 下記サンプルの
MutualClass を参照。
CheckUnderDestroyer
Add
参考
→ ガーベージコレクション (GC)
DestroyerClass
→ 相互参照しているときの Class_Terminate
Case1:
Case1: a.Class_Terminate
Case1: b.Class_Terminate
Case2:
End of Main
もし、ここ以降でデストラクターが動くときは、プログラム終了時にすべての
オブジェクトを削除することによるデストラクター呼び出しです。
Case2: a.Class_Terminate
Case2: b.Class_Terminate
表示例：
関連
→ LifeGroupClass
LifeGroupClass
の使用を推奨します。
注意
DestroyerClass の代わりに
← ▼ ▲
Add (DestroyerClass)
Sub DestroyerClass::Add( Object as variant )
相互参照するオブジェクトを登録します。
【引数】
Object
登録するオブジェクト
<< DestroyerClass
本関数は、Object の IsDestroyer 属性（プロパティ）を True に設定します。
DestroyerClass が削除されるタイミングで、Object の DestroyReferences メソッドが
呼ばれます。
← ▼ ▲
Remove (DestroyerClass)
Sub DestroyerClass::Remove( Object as variant )
登録から除外します。
【引数】
Object
除外するオブジェクト
<< DestroyerClass
DestroyerClass が削除されるときよりも早く削除するオブジェクトを指定してください。
本関数は、Object の IsDestroyer 属性（プロパティ）を False に設定します。
← ▼ ▲
CheckUnderDestroyer
Sub CheckUnderDestroyer( Object as variant )
Destroyer によって管理されていなければ、エラーにします。
←
↓