How to terminate an object that's in a collection

V

vivmaha

"Coll" is a standard VBA Collection object.
The first item in it is a MyClass object.
How do I delete this object? (and free the memory used)

This does not work:
Coll.remove 1 'The memory of item 1 is still allocated

This crashes:
Set Coll.item(1) = nothing '<Crash occurs here (Err 438)
Coll.remove 1

Thanks.
 
P

Peter T

There does appear to be something particular about removing the last class
object/item in a collection. Although the last item is removed from the
collection as expected, the "last class" it seems is only destroyed when the
routine terminates.

Try commenting/uncommenting the various tests in the following -

Dim col As Collection

Sub test()
Set col = New Collection
Dim cls As Class1, s$
For i = 1 To 3
Set cls = New Class1
cls.sName = "class" & i
col.Add cls, cls.sName
Next

' this triggers the terminate immediately
'col.Remove "class2" ' or by index simply 2

' but this only triggers the terminate when the routine ends
'col.Remove "class3" ' or 3

'For i = 1 To 3
For i = col.Count To 1 Step -1
col.Remove i ' or "class" & i
Next

Debug.Print col.Count ' 0 as expected

'Set col = Nothing

End Sub ' class3 always terminates here


'''' in Class1
Public sName As String
Private Sub Class_Terminate()
Debug.Print "Class_Terminate " & sName
End Sub

Regards,
Peter T
 
G

George Nicholson

Coll.Add MyClass, "Test"
Coll.Remove 1 'removes item from collection, but MyClass still exists
Set MyClass = Nothing 'Removes MyClass from memory

You are adding an object to the collection, but the object also exists in
memory outside of the collection. Any given object could possibly exist in
multiple collections. (Pretty sure that with custom classes you are adding a
copy of the object to a collection. In my experience, changing a property of
a custom object in one collection will not "update" the same object's
property in another collection.)

Removing an object from a collection won't remove it from memory, unless it
is the last outstanding reference to the object.

Coll.Add MyClass, "Test"
Set MyClass = Nothing 'removes 1st instance from memory (coll.count still
equals 1)
Coll.Remove 1 'removes object from collection and memory

HTH,
 
P

Peter T

Ignore all this, dumb!

Obviously class3 always terminated at the end of the routine as a ref still
existed to the last class due to this

Set cls = New Class1

IOW, removing class objects from the collection should destroy the class,
providing no other reference exists pointing to the same class.

Regards,
Peter T
 
P

Peter T

Indeed George, while the MyClass reference exists so does the Class, my
mistake in adjacent post.

Not sure about this bit though -
Pretty sure that with custom classes you are adding a
copy of the object to a collection

Adding the class object to the collection adds a pointer to the sole class
object, which may also be referenced by other object variables, ?
Coll.Add MyClass, "Test"
Coll.Remove 1 'removes item from collection, but MyClass still exists
Set MyClass = Nothing 'Removes MyClass from memory

could also do this -

Coll.Add MyClass, "Test"
Set MyClass = Nothing ' or goes out of scope
Coll.Remove 1 'removes item from collection, and destroys the class

Regards,
Peter T
 
V

vivmaha

Hi,

My problem is that I dont have references to things in the collection.
I can iterate through the collection, instance the items, and do exactly
what u did, but i wanted to know why the "Set collec.item(1) = nothing"
throws an error.

Thanks for provided a work around though.
 
G

George Nicholson

Pretty sure that with custom classes you are adding a
In my experience, if i create an object from a custom class with a
"StartTime" property, then add that object to 2 different collections,
changing the StartTime of one will not change the StartTime in the other.

My memory is pretty clear on this, but it is not clear on whether there
might have been something else involved. Maybe it was a custom collection
that I hadn't set up properly.
 
V

vivmaha

I tested this out.

Class1:
Public s As Integer

Module1:
Public Sub run()

Dim C As Collection
Set C = New Collection

Dim D As Collection
Set D = New Collection


Dim tmp As Class1
Set tmp = New Class1

C.Add tmp
tmp.s = 1

D.Add tmp
tmp.s = 2

MsgBox C.Item(1).s
MsgBox D.Item(1).s

End Sub

Output:
2,2

Therefore, they are added by ref.
 
P

Peter T

Sub test()
Dim col As Collection
Dim MyClass As Class1

Set MyClass = New Class1

Set col = New Collection
col.Add MyClass, "A"

MyClass.propNum = 111
Debug.Print col(1).propNum ' 111

col(1).propNum = 222
Debug.Print MyClass.propNum ' 222

End Sub


' code Class1
Dim mNum As Long
Public Property Let propNum(n&)
mNum = n
End Property
Public Property Get propNum&()
propNum = mNum
End Property

In the above MyClass and col(1) both refer to the same instance of the class

Regards,
Peter T
 
P

Peter T

Thanks for provided a work around though.

It wasn't a workaround, it was the correct way to remove an item from a
collection, and with no other pointers to the class will destroy the class
(some rare exceptions with 'circular object references')

Probably best not to think of a collection item as an object variable.

Another way to refer to multiple instances of the same class would be with
an array, eg

Dim arrClass() as Class1
Redim arrClass(0 to 3)
Set arrClass(0) = New Class1
' code
arrClass(0).myMethod blah ' intellisence here
set arrClass(0) = nothing

Regards,
Peter T
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top