0

i have an issue with dynamic arrays being passed to class byVal instead byRef, so simplified class, cArray

Option Explicit

Private mArray() As String

Public Sub init(ByRef iArray() As String)
    mArray = iArray
End Sub

Public Property Get count() As Long
    count = UBound(mArray) - LBound(mArray)
End Property

Public Property Get item(iIndex As Long) As String
    item = mArray(iIndex)
End Property

and simple function in module

Private Sub arrTest()
    Dim arr() As String, cont As cArray
    ReDim arr(0 To 1)

    arr(0) = "value0"
    arr(1) = "value1"

    Set cont = New cArray
    cont.init arr

    arr(1) = "newValue1"
    Debug.Print cont.item(1), arr(1) 'will print value1, newValue1 even though is expected to be same

    ReDim Preserve arr(0 To 2)
    arr(2) = "value2"

    Debug.Print cont.count 'will print 1
End Sub

so, question is, is this bug? normal behavior? something else?

5
  • This is normal - an object will typically have a longer lifespan than an array, so this prevents the array's memory from being freed by anything other than the object itself. Commented Jan 9, 2017 at 14:10
  • @TimWilliams - consider Dim x() As Long: someobj.ArrayProperty = x: Erase x. How is someobj supposed to know whether x has been freed or not? Arrays aren't reference types in VBA, so there isn't really a safe way to determine if the calling code or the object is responsible for cleaning up the array's memory allocation (they aren't reference counted). Dynamic arrays in particular would problematic in this regard because they can be ReDim'd. Commented Jan 9, 2017 at 17:05
  • 1
    The issue is you're making an assignment of Array to mArray - that is a by value assignment (ie. it creates a copy of the array in mArray instead of creating an additional pointer to the original array you passed in). So, you can make changes to iArray in the init Sub and those will be reflected in arrTest but that does not create any link between arr and mArray Commented Jan 9, 2017 at 17:05
  • @Comintern - yes I figured it out: thanks for the explanation. Also - stackoverflow.com/questions/16323776/… but that's more about Variants than Arrays... Commented Jan 9, 2017 at 17:08
  • I asked a similar question, which might have helpful answers for you: stackoverflow.com/questions/25328975/array-as-a-class-member Commented Jan 9, 2017 at 23:12

1 Answer 1

0

Actually, the array is passed by reference. The problem comes at the assignment.

In VBA assigning one array variable to another array variable or one string variable to another string variable creates a copy though there are ways around this using Variants or CopyMemory, for example. If you're interested, drop a comment.

I can demonstrate this by using VarPtr to get the actual addresses for comparison. Let's add a few lines to your code...

cArray

Option Explicit

Private mArray() As String

Public Sub init(ByRef iArray() As String)
    Debug.Print "The address of the function parameter is: " & VarPtr(iArray(0)) '<----- add this line
    mArray = iArray
    Debug.Print "The address of the mArray class member is: " & VarPtr(mArray(0)) '<----- add this line
End Sub

Public Property Get count() As Long
    count = UBound(mArray) - LBound(mArray)
End Property

Public Property Get item(iIndex As Long) As String
    item = mArray(iIndex)
End Property

mdlMain

Private Sub arrTest()
    Dim arr() As String, cont As cArray
    ReDim arr(0 To 1)

    arr(0) = "value0"
    arr(1) = "value1"

    Debug.Print "The address of the newly dimensioned and initialized arr is: " & VarPtr(arr(0)) '<----- add this line

    Set cont = New cArray
    cont.init arr

    arr(1) = "newValue1"

    Debug.Print cont.item(1), arr(1) 'will print value1, newValue1 even though is expected to be same

    ReDim Preserve arr(0 To 2)
    arr(2) = "value2"

    Debug.Print cont.count 'will print 1
End Sub

When I run this, I get (the memory addresses will likely be different for you):

The address of the newly dimensioned and initialized arr is: 192524056
The address of the function parameter is: 192524056 The address of the
mArray class member is: 192524040 
value1        newValue1  1

So you can see that the actual function parameter WAS passed by reference, but the assignment created a copy.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.