Dynamic Object and Data Lifetime

Lifetime of Dynamic Object and its Data, created from declaration keyword 
for dynamic memory allocation.

Preamble:

   * The Lifetime of an object (and of its data) is the time period in 
     which its identifier variable exists (and refers to valid data). But 
     in absolute terms, the identifier variable of the object and its 
     associated data can have two independent lifetimes (the Scope 
     referring to the program part where the identifier variable is 
     visible).
   * The dynamic objects considered are the predefined pseudo-objects such 
     as the variable-length strings/arrays, and the instances of complex 
     UDT (with its own dynamic data allocated).
   * Simple variables but allocated in a dynamic way are also considered, 
     and finally the dynamic objects which are allocated as well in a 
     dynamic way.
   * The declaration keywords for dynamic memory allocation are: 
     'Allocate'/'Callocate'/'Reallocate', 'New', 'ImageCreate' (for 
     deallocation: 'Deallocate', 'Delete', 'ImageDestroy').

   For such objects and data dynamically allocated as defined above, the 
   lifetime of the identifier variable of the object generally matches the 
   surrounding scope (otherwise it can be greater than this one), but the 
   lifetime of associated data may mismatch this one because the 
   allocation/deallocation of associated data is triggered by the user 
   himself.

Case of predefined pseudo-objects allocated in a static way by user
   Even though these predefined type variables (variable-length strings (1)
   , or variable-length arrays (2)) are allocated in a static way as 
   follows (or similar syntax):
         (1)	Dim [Shared] As String stringname ...
      or
         (2)	Dim [Shared] As datatype arrayname() ...
   these variables can be considered as dynamic pseudo-objects because they 
   are assemblies of two entities:
      - a descriptor associated to the identifier variable (stringname (1), 
      or arrayname() (2)), the first entity
      - referencing a dynamic allocation in memory (the string data (1), or 
      the array data (2)), the second entity (unnamed).

   The descriptor is allocated in the .BSS or .DATA section, if 'Shared' is 
   used, otherwise on the program stack.
   The string data are allocated/reallocated/deallocated in the heap by 
   string assigning, also updating the descriptor accordingly (assigning an 
   empty string does not destroy the descriptor but just resets it).
   The array data are allocated/reallocated in the heap by 'Redim' and 
   deallocated by 'Erase', also updating the descriptor accordingly 
   ('Erase' does not destroy the descriptor but just re-initializes it).
   So whatever such a user command applied, the identifier variable remains 
   always defined in its scope, at cons the memory allocation can be 
   dynamically modified/freed in this same scope (accordingly to the user 
   command).

Case of dynamic objects allocated in a static way by user
   The user can also define a dynamic object through a complex UDT with 
   member procedures to allocate/reallocate/deallocate dynamic data 
   associated to it.
   The member procedures normally used to perform this are the constructors 
   (for allocation), the assignment operators (for reallocation) and the 
   destructor (for deallocation).

   Even if the object identifier variable is allocated in a static way 
   (similarly to above):
      Dim [Shared] As complexUDT instancename ...
   inducing automatic allocation and deallocation of object data following 
   the identifier variable scope (by means of implicit call to UDT 
   constructor then destructor), between the two, the dynamic data 
   allocation can be deeply impacted by user commands (such as explicit 
   calls to operators overloaded for the UDT).

Case of simple variables but allocated in a dynamic way by user
   The keywords ('Allocate', 'Reallocate', 'New', 'ImageCreate'), used to 
   declare a dynamic allocation, create an unnamed entity whose the 
   lifetime depends on other user commands ('Deallocate', 'Delete', 
   'ImageDestroy').
   Generally, these allocation keywords are included in expressions used to 
   initialize (1|3), or assign (2|4), a simple variable (a pointer (1|2), 
   or a reference (3|4)), as for example:
            (1)	Dim As datatype Ptr DATApointername = New datatype ...
         or
            (2)	Dim [Shared] As datatype Ptr DATApointername
            (2)	.....
            (2)	DATApointername = New datatype ...
      or
            (3)	Dim ByRef As datatype DATAreferencename = *New datatype ...
         or
            (4)	Dim [Shared] ByRef As datatype DATAreferencename = *CPtr(
            datatype Ptr, 0)
            (4)	.....
            (4)	@DATAreferencename = New datatype ...

   Therefore, in this case, there are two distinct entities:
      - a named pointer (1|2) or a reference (3|4), the first entity,
      - pointing (1|2) or referring (3|4) to an allocated memory, the 
      second entity (unnamed).

   Do not confuse the two entities, each has its own lifetime.
   'Deallocate', 'Delete', 'ImageDestroy', deallocating only the second 
   entity (not the first), as for example using:
         (1|2)	Delete DATApointername
      or
         (3|4)	Delete @DATAreferencename

Case of dynamic objects allocated as well in a dynamic way by user
   The dynamic object (complex UDT) can also be allocated as well in a 
   dynamic way (similarly to above), by initializing (1|3), or assigning 
   (2|4), a simple variable (a pointer (1|2), or a reference (3|4)), as for 
   example:
            (1)	Dim As complexUDT Ptr UDTpointername = New complexUDT ...
         or
            (2)	Dim [Shared] As complexUDT Ptr UDTpointername
            (2)	.....
            (2)	UDTpointername = New complexUDT ...
      or
            (3)	Dim ByRef As complexUDT UDTreferencename = *New complexUDT 
            ...
         or
            (4)	Dim [Shared] ByRef As complexUDT UDTreferencename = *CPtr(
            complexUDT Ptr, 0)
            (4)	.....
            (4)	@UDTreferencename = New complexUDT ...

   Therefore, in this last case, three entities can be considered:
      - a named pointer (1|2) or a reference (3|4), the first entity,
      - pointing (1|2) or referring (3|4) to the allocated fields of the 
      object, the second entity (unnamed),
      - and addressing the dynamic allocated associated data, the third 
      entity (unnamed).

   Do not confuse the three entities, each has its own lifetime.
   'Delete' deallocates the second entity (not the first), which begins to 
   deallocate the third at first (by calling its destructor), as for 
   example using:
         (1|2)	Delete UDTpointername
      or
         (3|4)	Delete @UDTreferencename

Example
   Dynamic object (complex UDT) allocated as well in a dynamic way by user:
      - first entity: the UDT reference, statically allocated on the 
      program stack,
      - second entity: the UDT instance with its zstring pointer field 
      (referred by the UDT reference), dynamically allocated in the heap by 
      the user,
      - third entity: the zstring data (referred by the zstring pointer 
      field), dynamically reallocated in the heap by the UDT procedure 
      members (constructors, let operator, destructor).
   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
            
Output:

   '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()

See also
   * Allocate, CAllocate, Reallocate, Deallocate
   * New (Expression), Delete (Statement)
   * ImageCreate, ImageDestroy
   * ReDim, Erase
   * Storage Classes
   * Variable Scope
   * Simple Variable Lifetime vs Scope

