Skip to content

动态对象与数据的生命周期


使用动态内存分配声明关键字创建的动态对象及其数据的生命周期。

前言:

  • 对象(及其数据)的生命周期是其标识符变量存在(且引用有效数据)的时间段。但从绝对意义上说,对象的标识符变量及其关联数据可以有两个独立的生命周期(作用域指标识符变量可见的程序部分)。
  • 所考虑的动态对象包括预定义伪对象,如可变长度字符串/数组,以及具有自身动态分配数据的复杂 UDT 实例。
  • 也考虑以动态方式分配的简单变量,以及同样以动态方式分配的动态对象。
  • 动态内存分配的声明关键字有:Allocate/Callocate/ReallocateNewImageCreate(释放对应:DeallocateDeleteImageDestroy)。

对于上述定义的动态分配的对象和数据,对象标识符变量的生命周期通常与周围的作用域相匹配(否则可以大于该作用域),但关联数据的生命周期可能与之不一致,因为关联数据的分配/释放是由用户自身触发的。

用户以静态方式分配的预定义伪对象

即使这些预定义类型变量(可变长度字符串 (1) 或可变长度数组 (2))以如下静态方式分配(或类似语法):

(1)Dim [Shared] As String stringname ...

(2)Dim [Shared] As datatype arrayname() ...

这些变量也可以被视为动态伪对象,因为它们是两个实体的组合:

  • 与标识符变量关联的描述符(stringname (1)arrayname() (2)),即第一个实体

  • 引用内存中的动态分配(字符串数据 (1) 或数组数据 (2)),即第二个实体(无名称)。

如果使用了 Shared,描述符分配在 .BSS 或 .DATA 段中,否则分配在程序栈上。

字符串数据通过字符串赋值在堆中分配/重新分配/释放,同时相应地更新描述符(赋空字符串不会销毁描述符,只是重置它)。

数组数据通过 Redim 在堆中分配/重新分配,通过 Erase 释放,同时相应地更新描述符(Erase 不销毁描述符,只是重新初始化它)。

因此,无论应用何种用户命令,标识符变量始终在其作用域内保持定义,而内存分配可以在同一作用域内动态修改/释放(根据用户命令)。

用户以静态方式分配的动态对象

用户也可以通过具有成员过程的复杂 UDT 来定义动态对象,这些成员过程用于分配/重新分配/释放与其关联的动态数据。

通常用于执行此操作的成员过程是构造函数(用于分配)、赋值运算符(用于重新分配)和析构函数(用于释放)。

即使对象标识符变量以静态方式分配(与上面类似):

Dim [Shared] As complexUDT instancename ...

这会通过隐式调用 UDT 构造函数然后析构函数,自动按照标识符变量的作用域来分配和释放对象数据,但在此期间,动态数据分配可能会受到用户命令的深刻影响(例如对 UDT 重载运算符的显式调用)。

用户以动态方式分配的简单变量

关键字(AllocateReallocateNewImageCreate)用于声明动态分配,创建一个无名实体,其生命周期取决于其他用户命令(DeallocateDeleteImageDestroy)。

通常,这些分配关键字包含在用于初始化 (1|3) 或赋值 (2|4) 简单变量(指针 (1|2) 或引用 (3|4))的表达式中,例如:

(1)Dim As datatype Ptr DATApointername = New datatype ...

(2)Dim [Shared] As datatype Ptr DATApointername

(2).....

(2)DATApointername = New datatype ...

(3)Dim Byref As datatype DATAreferencename = *New datatype ...

(4)Dim [Shared] Byref As datatype DATAreferencename = *Cptr(datatype Ptr, 0)

(4).....

(4)@DATAreferencename = New datatype ...

因此,在这种情况下,存在两个不同的实体:

  • 有名指针 (1|2) 或引用 (3|4),即第一个实体,

  • 指向 (1|2) 或引用 (3|4) 已分配内存的,即第二个实体(无名称)。

不要混淆这两个实体,每个实体都有自己的生命周期。

DeallocateDeleteImageDestroy 只释放第二个实体(不释放第一个),例如使用:

(1|2)Delete DATApointername

(3|4)Delete @DATAreferencename

用户也以动态方式分配的动态对象

动态对象(复杂 UDT)也可以以动态方式分配(与上面类似),通过初始化 (1|3) 或赋值 (2|4) 简单变量(指针 (1|2) 或引用 (3|4)),例如:

(1)Dim As complexUDT Ptr UDTpointername = New complexUDT ...

(2)Dim [Shared] As complexUDT Ptr UDTpointername

(2).....

(2)UDTpointername = New complexUDT ...

(3)Dim Byref As complexUDT UDTreferencename = *New complexUDT ...

(4)Dim [Shared] Byref As complexUDT UDTreferencename = *Cptr(complexUDT Ptr, 0)

(4).....

(4)@UDTreferencename = New complexUDT ...

因此,在最后这种情况下,可以考虑三个实体:

  • 有名指针 (1|2) 或引用 (3|4),即第一个实体,

  • 指向 (1|2) 或引用 (3|4) 已分配的对象字段,即第二个实体(无名称),

  • 以及寻址动态分配的关联数据,即第三个实体(无名称)。

不要混淆这三个实体,每个实体都有自己的生命周期。

Delete 释放第二个实体(不释放第一个),它首先开始释放第三个实体(通过调用其析构函数),例如使用:

(1|2)Delete UDTpointername

(3|4)Delete @UDTreferencename

示例

用户也以动态方式分配的动态对象(复杂 UDT):

  • 第一个实体:UDT 引用,静态分配在程序栈上,

  • 第二个实体:UDT 实例(包含其 zstring 指针字段)(由 UDT 引用引用),由用户在堆中动态分配,

  • 第三个实体:zstring 数据(由 zstring 指针字段引用),由 UDT 过程成员(构造函数、let 运算符、析构函数)在堆中动态重新分配。

start GeSHi

vb
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

end GeSHi

输出:

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

参见

返回 目录

基于 FreeBASIC 官方文档翻译 如有侵权请联系我们删除
FreeBASIC 是开源项目,与微软公司无隶属关系