How to destroy an object
Asked Answered
M

3

19

It seems that Set Object = Nothing didn't destroy the Fs Object in this code:

Sub Test2()
    Dim Fs As New FileSystemObject
    Set Fs = Nothing
    MsgBox Fs.Drives.Count ' this line works
End Sub

The last line works with no errors!. thats mean Fs Object is still exists, right?.

So how to destroy this Fs Object.

Mycenae answered 10/2, 2017 at 16:58 Comment(6)
Let it go out of scope? Why do you feel a need to destroy it?Tricot
@Comintern, I use this object to read an write to text file saved in TrueCrypt volume, and after using it I can't dismount this volume, maybe if I destroy it I can dismount this volume.Mycenae
Possible duplicate of VBA: Difference in two ways of declaring a new object? (Trying to understand why my solution works)Tricot
That sounds like an issue with whatever code you're using to read and write the text file. The code above won't hold an FSO reference after it completes.Tricot
@Tricot in some sense a duplicate, but someone who didn't know the answer to the question wouldn't even suspect that it is a duplicate and wouldn't know how to search for it.Emf
@Mat'sMug, I was eagerly waiting for your explanation. Cannot say I got it though. But I've got something to think over for a while...Seeker
G
23

Another way to ensure proper destruction of an object, is to yield its object reference to a With block (i.e. don't declare a local variable):

Sub Test()
    With New FileSystemObject
        MsgBox .Drives.Count
    End With
End Sub

The object only ever exists inside the With block, and when execution reaches the End With token, if you try it with a custom class module you'll notice that the the class' Class_Terminate handler runs, effectively confirming the proper destruction of the object.

As for the As New quirk, as was already explained, if you intend to set the object reference to Nothing inside that scope, don't declare it with As New, because VBA will set the object reference to Nothing, but will also happily ("helpfully") create a new instance for you as soon as you re-reference it again, be it only to verify that the object Is Nothing.

Side note, this (annoying) counter-intuitive behavior is specifically what's behind the reasoning for Rubberduck's Object variable is self-assigned code inspection:

RD website's inspection results

(note: if you've got code you want to inspect, know that it runs much faster in the actual VBE than on the website)

(if it wasn't clear already: I'm heavily involved with the Rubberduck project)

Grandmamma answered 10/2, 2017 at 18:46 Comment(3)
Thank a lot @Mat's Mug. user3598756 and Zerk answers are great and help me, but I think your answer is the best and should be the accepted answer to help other users too.Mycenae
Hmm, I didn't mean to steal a checkmark here, only to provide additional information - thanks anyway!Grandmamma
I was know about Dim then Set and test it before I post my question, but I was looking for additional information like your answer, Thank you again.Mycenae
S
20

it must have to do with the "declare & instantiate" pattern, most often addressed as a "to be avoided" pattern

if you split them, you get Nothing after setting it to:

Sub Test2()
    Dim Fs As FileSystemObject
    Set Fs = New FileSystemObject
    Set Fs = Nothing
    MsgBox Fs.Drives.Count ' this line DOESN'T work
End Sub
Seeker answered 10/2, 2017 at 17:7 Comment(1)
Thanks a lot user3598756, and i'm sorry but I think @Mat's Mug posts a great answer.Mycenae
A
12

This amended code seems to work fine. Seems a nuance with the dim/new on the same line. Hopefully someone else can give a better idea as to the reasoning.

As others have commented, if it is a dim within the sub then it will be collected after the sub completes anyway.

Sub Test2()
    Dim Fs As FileSystemObject
    Set Fs = New FileSystemObject
    Set Fs = Nothing
End Sub
Ante answered 10/2, 2017 at 17:6 Comment(2)
I had the same issue with a collection that wasn't clearing after code finished running. I had declared at the top of my module like this: Dim coll As New Collection. I removed the New keyword then added this inside my sub: Set Coll = New Collection. I tried different methods like = nothing but this was the only thing that worked.Mcchesney
@SendETHToThisAddress, if you had put this as an answer, I'd upvote it. That's what worked for me, as well.Grenada

© 2022 - 2024 — McMap. All rights reserved.