变体类型的对象数组元素由 With 语句释放

问题描述 投票:0回答:1

如果对象数组声明为 Variant 类型(以便轻松检查它是否使用 IsEmpty 函数初始化),那么,如果随后定义的数组元素被引用为 With 的对象表达式 语句(例如

With VariantObjArray(i) ...
),那么该对象变量数组元素将被错误地释放(尽管 With 语句的对象变量的隐式副本将正确地用于单个后续执行 - 通过 With 的范围陈述)。 此外,数组元素对象变量的错误释放可能是内存泄漏,因为它是在执行 With 表达式时立即发生的,而不是任何标准释放机制的结果,例如退出 With 语句或从子例程返回或被显式设置为 Nothing。

Sub DemoVariantObjArrayBug()
    Dim i As Integer
    Dim NextWkSh As Worksheet
    Static VariantObjArray As Variant

    If IsEmpty(VariantObjArray) Then 'Check to avoid unnecessary re-allocation of static or global array variable
        ReDim VariantObjArray(1 To ThisWorkbook.Worksheets.Count)
        For Each NextWkSh In ThisWorkbook.Worksheets
            i = i + 1: Set VariantObjArray(i) = ThisWorkbook.Worksheets(i)
        Next NextWkSh
    End If
    
Stop 'and, to observe the bug, open the Locals window, expand its view of VariantObjArray, single step through
     'the following code and observe each VariantObjArray element being deallocated with each cycle's execution
     'of the "With" statement:
      
    For i = LBound(VariantObjArray) To UBound(VariantObjArray)
           With VariantObjArray(i) 'The bug workaround is to, instead of this, do something like the following...
'            Dim SomeWkSh As Object: Set SomeWkSh = VariantObjArray(i)
'            With SomeWkSh
                Debug.Print """" & .Name & """: CodeName = " & .CodeName & ", Index = " & .Index
            End With
    Next i
End Sub

解决方法是显式使用中间对象变量,如上面的备用(最初注释)代码所示。 我的问题是:

  1. 我一直找不到关于这个错误的任何网络讨论,那么它真的是一个直到现在还没有人遇到过的错误吗?
  2. 或者是最近引入的新错误,包括我当前版本的 Excel,Microsoft 365 MSO (16.0.14326.21052) 64 位?
  3. 是64位Office特有的吗?
  4. 它实际上是分配对象内存泄漏还是仅仅是对象指针丢失?
arrays vba object variant
1个回答
0
投票

Cristian Buse 提供了一个更简洁的 bug 解决方法(见上面的评论)。这是我的演示代码和他的解决方法:

Sub DemoVariantObjArrayBug()
    Dim i As Integer
    Dim NextWkSh As Worksheet
    Static VariantObjArray As Variant

    If IsEmpty(VariantObjArray) Then 'Check to avoid unnecessary re-allocation of static or global array variable
    
        ReDim VariantObjArray(1 To ThisWorkbook.Worksheets.Count) '*** Naive ReDim that sets the stage for the bug
'        ReDim VariantObjArray(1 To ThisWorkbook.Worksheets.Count) As Worksheet '*** Cristian Buse's workaround

        For Each NextWkSh In ThisWorkbook.Worksheets
            i = i + 1: Set VariantObjArray(i) = ThisWorkbook.Worksheets(i)
        Next NextWkSh
    End If
    
Stop 'and, to observe the bug, open the Locals window, expand its view of VariantObjArray, single step through
     'the following code and observe each VariantObjArray element being deallocated with each cycle's execution
     'of the "With" statement:
      
    For i = LBound(VariantObjArray) To UBound(VariantObjArray)
           With VariantObjArray(i) 'The bug workaround is to, instead of naively re-dimensioning the array as
                                   'an (implicit) Variant, above, re-dimension it as a specific type (Worksheet).
                                   
                Debug.Print """" & .Name & """: CodeName = " & .CodeName & ", Index = " & .Index
            End With
    Next i
End Sub
© www.soinside.com 2019 - 2024. All rights reserved.