動的メモリ割り当ての宣言キーワードから作成された、
Dynamic Object と、その
Data の
有効期間。
序文:
- オブジェクト(およびそのデータ)の有効期間は、その識別子変数が存在する(および有効なデータを参照する)期間です。
ただし、絶対条件では、オブジェクトの識別子変数とそれに関連するデータには、2つの独立した有効期間(識別子変数が表示される、プログラム部分を参照するスコープ)があります。
- 考慮される動的オブジェクトは、可変長文字列/配列などの事前定義された擬似オブジェクト、および複雑な UDT のインスタンス(独自の動的データが割り当てられている)です。
- 動的な方法で割り当てられた単純な変数も考慮され、最後に同様に動的な方法で割り当てられた動的オブジェクトも考慮されます。
- 動的メモリ割り当ての宣言キーワードは、'Allocate'/'Callocate'/'Reallocate', 'New', 'ImageCreate'(割り当て解除は: 'Deallocate', 'Delete', 'ImageDestroy')です。
上記のように、動的に割り当てられた、このようなオブジェクトとデータの場合、オブジェクトの識別子変数の有効期間は、通常周囲のスコープと一致します(そうでない場合はこれよりも長くなる可能性があります)。
しかし、関連付けられたデータの有効期間は、関連付けられたデータの割り当て/割り当て解除はユーザー自身によってトリガーされるため、これと一致しません。
ユーザーによって静的な方法で割り当てられた、定義済みの擬似オブジェクトの場合
これらの事前定義された型変数(可変長文字列
(1) または可変長配列
(2))は、次のように静的な方法で割り当てられます(または同様の構文で):
これらの変数は、2つのエンティティの集合なので、動的な擬似オブジェクト、と見なすことができます:
- 識別子変数(stringname (1), か arrayname() (2))に関連付けられた記述子、最初のエンティティ
- メモリ内の動的割り当て(文字列データ (1) または配列データ (2))を参照、2番目のエンティティ(名前なし)
記述子は、'Shared' が使用される場合は、.BSS または .DATA セクションに割り当てられ、そうでない場合は、プログラム・スタックに割り当てられます。
文字列データは、文字列の割り当てによって、ヒープ内で 割り当て/再割り当て/割り当て解除 され、それに応じて記述子も更新されます(空の文字列を割り当てても記述子は破棄されず、リセットされます)。
配列データは、'Redim' によって、ヒープ内で 割り当て/再割り当て され、'Erase' によって割り当て解除され、それに応じて記述子も更新されます('Erase' は記述子を破壊せず、再初期化します)。
そのため、このようなユーザーコマンドが適用されても、識別子変数は、スコープ内で常に定義されたままになり、メモリ割り当ては、この同じスコープ内で(ユーザー・コマンドに従って)動的に 変更/解放 できます。
ユーザーによって静的な方法で割り当てられた、動的オブジェクトの場合
ユーザーは、また、関連付けられた動的データを 割り当て/再割り当て/割り当て解除 するメンバー手続きを使って、複雑な UDT を介して、動的オブジェクトを定義できます。
これを実行するために通常使われるメンバー手続きは、コンストラクタ(割り当て用)、割り当て演算子(再割り当て用)、およびデストラクタ(割り当て解除用)です。
オブジェクト識別子変数が、静的な方法で割り当てられている場合(上記と同様):
識別子変数スコープに従って、オブジェクトデータの、自動割り当てと割り当て解除を誘導します(UDTコンストラクターとデストラクターへの暗黙的な呼び出しによる)。
2つの間で、動的データ割り当ては、ユーザーコマンドによって、大きく影響を受ける可能性があります(UDT用にオーバーロードされた演算子の明示的な呼び出しなど)。
単純な変数だが、ユーザーによって動的に割り当てられた場合
動的割り当てを宣言するために使われる、キーワード('Allocate', 'Reallocate', 'New', 'ImageCreate')は、有効期間が他のユーザーコマンド('Deallocate', 'Delete', 'ImageDestroy')に依存する、名前のないエンティティを作成します。
一般的に、これらの割り当てキーワードは、初期化
(1|3) または割り当て
(2|4)、単純変数(ポインター
(1|2)、または参照
(3|4))に使われる式に含まれます。 例:
したがって、この場合、2つの異なるエンティティがあります:
- 名前付きポインター (1|2) または参照 (3|4)、最初のエンティティ、
- 割り当てられたメモリを、指す (1|2) または参照 (3|4) 、2番目のエンティティ(名前なし)。
2つのエンティティを混同しないでください。それぞれが独自の有効期間を持っています。
'Deallocate', 'Delete', 'ImageDestroy'、2番目のエンティティ(最初のエンティティではない)だけの割り当てを解除します。次をの用例を参照下さい:
ユーザーによって動的に割り当てられた動的オブジェクトの場合
動的オブジェクト(複雑な UDT)は、単純な変数(ポインター
(1|2)、または参照
(3|4))を、初期化
(1|3) または割り当て
(2|4) することにより、動的(上記と同様)に、割り当てることもできます。例として:
(1) Dim As complexUDT Ptr UDTpointername = New complexUDT ...
又は
(2) Dim [Shared] As complexUDT Ptr UDTpointername
(2) .....
(2) UDTpointername = New complexUDT ...
又は
したがって、この最後のケースでは、3つのエンティティを考慮することができます:
- 名前付きポインター (1|2) または参照 (3|4)、最初のエンティティ、
- オブジェクトの割り当てられた項目を、指す (1|2) または参照する (3|4) 、2番目のエンティティ(名前なし)、
- 動的に割り当てられた関連データをアドレスする、3番目のエンティティ(名前なし)。
3つのエンティティを混同しないでください。それぞれが独自の存続期間を持っています。
'Delete' は、2番目のエンティティ(最初ではなく)の割り当てを解除し、これにより、最初に 3番目のエンティティの割り当てが解除されます。次をの用例を参照下さい:
例
ユーザーによって動的に割り当てられた動的オブジェクト(複雑な UDT):
- 最初のエンティティ:UDT 参照、プログラム・スタックに、静的に割り当て
- 2番目のエンティティ:zstring ポインター項目(UDT 参照によって参照される)を持つ UDT インスタンス、ユーザーによって動的にヒープに割り当て
- 3番目のエンティティ:zstring データ(zstring ポインター項目によって参照される)。UDT 手続きメンバー(コンストラクタ、let 演算子、デストラクタ)によってヒープに動的に再割り当て
Type complexUDT
Public:
Declare Constructor ()
Declare Constructor (ByVal p As ZString Ptr)
Declare Operator Let (ByVal p As ZString Ptr)
Declare Operator Cast () As String
Declare Property info () As String ' allocation address, allocation size, string length
Declare Destructor ()
Private:
Dim As ZString Ptr pz
End Type
Declare Sub prntInfo_printString (ByRef u As complexUDT)
Print "'Dim Byref As complexUDT ref = *New complexUDT(""Beginning"")':"
Dim ByRef As complexUDT ref = *New complexUDT("Beginning")
prntInfo_printString(ref)
Print "'ref = """"':"
ref = ""
prntInfo_printString(ref)
Print "'ref = ""FreeBASIC""':"
ref = "FreeBASIC"
prntInfo_printString(ref)
Print "'ref = ""Programmer's Guide / Declarations / Dynamic Object and Data Lifetime""':"
ref = "Programmer's Guide / Declarations / Dynamic Object and Data Lifetime"
prntInfo_printString(ref)
Print "'ref.Destructor()':"
ref.Destructor()
prntInfo_printString(ref)
Print "'ref.Constructor()':"
ref.Constructor()
prntInfo_printString(ref)
Print "'ref.Constructor(""End"")':"
ref.Constructor("End")
prntInfo_printString(ref)
Print "'Delete @ref':"
Delete @ref
@ref = 0 ' systematic safety to avoid double-delete on same allocation
Sleep
Constructor complexUDT ()
Print " complexUDT.Constructor()"
This.pz = Reallocate(This.pz, 1)
(*This.pz)[0] = 0
End Constructor
Constructor complexUDT (ByVal p As ZString Ptr)
Print " complexUDT.Constructor(Byval As Zstring Ptr)"
This.pz = Reallocate(This.pz, Len(*p) + 1)
*This.pz = *p
End Constructor
Operator complexUDT.Let (ByVal p As ZString Ptr)
Print " complexUDT.Let(Byval As Zstring Ptr)"
This.pz = Reallocate(This.pz, Len(*p) + 1)
*This.pz = *p
End Operator
Operator complexUDT.Cast () As String
Return """" & *This.pz & """"
End Operator
Property complexUDT.info () As String
Return "&h" & Hex(This.pz, SizeOf(Any Ptr) * 2) & ", " & _ ' allocation address
Len(*This.pz) + Sgn(Cast(Integer, This.pz)) & ", " & _ ' allocation size
Len(*This.pz) ' string length
End Property
Destructor complexUDT ()
Print " complexUDT.Destructor()"
This.pz = Reallocate(This.pz, 0)
End Destructor
Sub prntInfo_printString (ByRef u As complexUDT)
Print " " & u.info
Print " " & u
Print
End Sub
出力:
'Dim Byref As complexUDT ref = *New complexUDT("Beginning")':
complexUDT.Constructor(Byval As Zstring Ptr)
&h001F2AD0, 10, 9
"Beginning"
'ref = ""':
complexUDT.Let(Byval As Zstring Ptr)
&h001F2AD0, 1, 0
""
'ref = "FreeBASIC"':
complexUDT.Let(Byval As Zstring Ptr)
&h001F2AD0, 10, 9
"FreeBASIC"
'ref = "Programmer's Guide / Declarations / Dynamic Object and Data Lifetime"':
complexUDT.Let(Byval As Zstring Ptr)
&h001F2AD0, 69, 68
"Programmer's Guide / Declarations / Dynamic Object and Data Lifetime"
'ref.Destructor()':
complexUDT.Destructor()
&h00000000, 0, 0
""
'ref.Constructor()':
complexUDT.Constructor()
&h001F2AD0, 1, 0
""
'ref.Constructor("End")':
complexUDT.Constructor(Byval As Zstring Ptr)
&h001F2AE0, 4, 3
"End"
'Delete @ref':
complexUDT.Destructor()
参照