Destructors and Freeing Memory Confusion

Hi,
I have a couple of questions about destroying objects that I’m a little fuzzy on.

  1. I read that it’s always a good idea to have a clean up method on an object that Nil’s out the object’s properties when the object is destroyed. However, if these objects are properties of a window, and you close the window ( and assuming there are no other persistent references to the instance pointed to by that property anywhere else in the app), then it is not necessary to have a destructor method on the object. Is this correct?

  2. I have a subclass of canvas, “myCanvas” that I use as a scroll view of container control objects. I dragged an instance of my subclass onto a window, “myCanvas1”. Will closing the window destroy myCanvas1 and all the container control objects it contains?

Or, do I need a destructor method with the container control object (there’s a remove button with each container control) And then call that same method in the close event of myCanvas1 for each container control that’s left on myCanvas1 when the window is closed?

Thank you

it’s not necessary to nil properties/variables. That’s going on automatically.
Just if you have a reference cycle, you need to cleanup that.

For the most part, you will never have to worry about any of this. The only time it’s really an issue is when you’ve kept a reference to an object (think global properties). And even then, you only need to nil it if you’re not using it any more. If it’s valid throughout the lifespan of the app it will get destroyed when the app closed.

Thanks guys, but I’m still a little confused.

I see that Xojo takes care of this for the most part, but what about when I have an array of objects?

Keeping with the example above, myCanvas has a property that is an array of myContainerControl. I dragged an instance of myCanvas, “myCanvas1” onto a window (not using ImplicitInstance). When I close the window, the array still holds all of the references to myContainerControl.

Even more confusing is that a reference to the window still exists, even after closing it!

Thank you

When you Close a Window, the Xojo framework should release its references to your Window. But if you’ve retained a reference, that won’t be released until you explicitly set it nil, or if it’s a property of some object/Window, that the object/Window is destroyed.

Your array property in the window will have all its objects released when the Window is actually destroyed. You could release them in the Close event handler if you like. Something like:

redim pMyArray(-1)

Ok, I understand now that I can free up memory that the array of objects is using, in the window’s close event, but what if I want to free up the memory used by the closed window? Set it to Nil, you say. But how…

I only have one property that holds a reference to the window. It’s a global property of the App.

win2 as myWindow2

There should only ever be one instance of myWindow2, but on my main window there’s a button with this code:

[code] dim i as integer
for i = 0 to WindowCount -1
if window(i) ISA myWindow2 then
// An instance of myWindow2 already exists. Show it. This should never happen, but just in case.
window(i).Show
return
end
next

// There is not an instance of myWindow2. Create one and show it.
win2 = New myWindow2 // Creates a reference or pointer to a new myWindow2 window.
win2.win_ShowCentered( Self )[/code]

The window is always closed when the user clicks on the OK or Cancel buttons of the window. But now I want to set win2 to Nil and free up memory. So since you can’t set a window to Nil in it’s own close event, where else could I set win2 = Nil ? I would like to free up memory that this win2 instance is holding, but is it worth it?

Thank you

Get rid of Win2 as a property
The code above makes it unnecessary since it will create an instance if / when you need it if there isn’t one already
Otherwise you HAVE to nil win2 as it will hold on to the reference to the window thereby making it that you DO have to clean up

Alter your code to (note win2 is a local now)

dim i as integer
    for i = 0 to WindowCount -1
      if window(i) ISA myWindow2 then
        // An instance of myWindow2 already exists. Show it.  This should never happen, but just in case.
        window(i).Show
        return
      end
    next
    
    // There is not an instance of myWindow2. Create one and show it.
    dim win2 as New myWindow2 // Creates a reference or pointer to a new myWindow2 window.
    win2.win_ShowCentered( Self )

There is no reason you can’t set win2=nil in the window’s Close event. What made you think that you can’t?

Thanks Norman. That definitely makes a better design. I was originally using a global property because I was using some unsightly code in a thread, but now that’s all fixed up.

Tim, I was working on encapsulating my code and I guess I was just stuck on using Self. Thanks.

Just two more questions on Destructors.

  1. Probably a dumb question but, Constructors are always public. Are Destructors always private?

  2. In the IDE I add a class, set it’s super to ContainerControl and call it “MyMainCC” to use as a superclass. I add a property on MyMainCC called “ParentWindow”. I also add a Destructor method that sets ParentWindow = Nil.

Then I create two different subclasses of MyMainCC called, “MyCC1” and “MyCC2”.

I create new instances of MyMainCC, like this:

dim oContainer as MyMainCC oContainer = new MyCC1( theWindow )
and

dim oContainer as MyMainCC oContainer = new MyCC2( theWindow )

When I close an instance of MyCC1 or MyCC2, the destructor method in MyMainCC is not called. Why?

I realize I never did a New MyMainCC anywhere, but MyMainCC is declared in the IDE.

Thank you

Actually, they are not always public. You might make the default (no argument) Constructor private (and empty) to force callers to use a Constructor that requires necessary parameters. If you had a base class, you might make your Constructors protected to prevent instantiation of the base.

Close ? or Nil ?
try this just as a test to see if the destructor gets called when it’s destroyed

dim oContainer as MyMainCC
oContainer = new MyCC1( theWindow )
oContainer = nil

Hmm yes that works. But I thought now that my window was self destructing properly, I didn’t have to worry about Nil 'ing.

To clarify, in the IDE I have created a subclass of Canvas called, “MyCanvas”. The window has a MyCanvas object dragged onto it, called “MyCanvas1”.

The superclass, MyCanvas, has a property:

Private aroContainers(-1) As MyMainCC

When I close the window, shouldn’t that in turn close MyCanvas1, which in turn will destroy all the references held in the aroContainers array?

Thank you

It should. Are you holding any other references to the containers or the canvas? Window.Close closes each of it’s controls, including embedded containers, and releases its reference to them. IF there are no other references to the control, it will be destructed. Note that the window itself and therefore any of its properties has not yet been destroyed. That happens later when the last reference to the window is dropped.

If you close the window and the containers are not destroyed, then there is still a reference to them somewhere.

Thanks Tim.

So I believe I may have a circular reference. Is this what a circular reference is?

The window has a MyCanvas object dragged onto it, called “MyCanvas1”.
MyCanvas1 has a property called “ParentWindow” and another property that’s an array of MyMainCC.
MyMainCC has a property called “ParentCanvas”.

So:

  1. The the Canvas references the Window and the Window references the Canvas.
  2. The Canvas references all container controls and each container control references the Canvas.

So in this case, do I set ParentCanvas = Nil in the Close event of MyMainCC, and set ParentWindow = Nil in the Close event of MyCanvas1 because a Destructor won’t work here?

Thank you

The framework takes care of #1 for you - the reference from window to canvas will be dropped, allowing the canvas to be destructed, which drops the reference back to the window.

#2 is your problem. The backlinks from the container to the canvas prevent the canvas from being destructed, which in turn prevents the container from being destructed. So, yes, set ParentCanvas = Nil in the Close event of MyMainCC.

Note that if you EmbedWithin(MyCanvas1, ...) keeping your own ParentCanvas property shouldn’t be necessary.

Thanks Tim. Adding ParentCanvas = Nil did the trick, but your last line got me thinking.

I am using EmbedWithin. So what you’re saying is that I don’t need to manage my own properties for the container’s parent canvas and the canvas’s parent window. If I need to access a method on the parent canvas of the container, I can just do this…

if self.Parent ISA MyCanvas then MyCanvas( self.Parent ).ContainerRemove( self ) end

Similarly, if I need to execute a method on the parent window of the container, I can do this…

if self.TrueWindow ISA WindowThatHasMyCanvasInIt then WindowThatHasMyCanvasInIt( self.TrueWindow ).ContainerRemoved( self ) end

Thank You