Still celebrating National IT Professionals Day with 3 months of free Premium Membership. Use Code ITDAY17

x
?
Solved

Free ListBox-Objects before closing the application

Posted on 2001-09-14
13
Medium Priority
?
201 Views
Last Modified: 2010-04-06
0
Comment
Question by:NicoleKabitzki
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 4
  • 3
  • 3
  • +2
13 Comments
 
LVL 22

Expert Comment

by:Mohammed Nasman
ID: 6482106
what do u want exactly?
0
 
LVL 8

Accepted Solution

by:
TOndrej earned 800 total points
ID: 6482164
you can do it in the form's OnDestroy:

procedure TForm1.ClearListBoxItems;
var
  I: Integer;
  MyObject: TObject;
begin
  with ListBox1.Items do
    for I := 0 to Count - 1 do
      Objects[I].Free;
end;

procedure TForm1.FormDestroy; // OnDestroy event handler
begin
  ClearListBoxItems;
end;
0
 
LVL 1

Expert Comment

by:malsoft
ID: 6482274
Just to expand a little on TOndrei's comment, I would add some exception handling into the clearing code, just in case something goes awry:

procedure TForm1.ClearListBoxItems;
var
  I: Integer;
begin
  with ListBox1.Items do
    for I := 0 to Pred(Count) do
      try
        Objects[I].Free;
      except
      end;
end;
0
Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 

Author Comment

by:NicoleKabitzki
ID: 6482354
0
 

Author Comment

by:NicoleKabitzki
ID: 6482355
0
 

Expert Comment

by:duti
ID: 6485553
A constructive comment on response above.

Normally it's not a good idea to eat exceptions.  Exceptions indicate problems, and they are very usefull when debugging. Certainly when your application is running at a customer's office, and you don't have Delphi there.

procedure TForm1.ClearListBoxItems;
var
 I: Integer;
begin
 with ListBox1.Items do
   for I := 0 to Count - 1 do
     if assigned(Objects[I]) then Objects[I].Free;
end;
0
 
LVL 8

Expert Comment

by:TOndrej
ID: 6485675
Hi duti,

TObject.Free checks for nil, therefore your check

if Assigned(Objects[I]) then ...

is not necessary.
0
 
LVL 1

Expert Comment

by:malsoft
ID: 6485752
duti,

Admittedly, "eating exceptions" is a BAD THING generally, but there are valid reasons for doing so in this instance. Plus, if you wanted to, you could add proper catching of the error(s) you might expect and re-raise the unhandled ones as needs be...

However, in this occasion we _do_ need to eat the exceptions. The loop in which the freeing is done will continue to work even if one object has already been Free'd, but the pointer referencing it is non-nil (which is normal for a Free operation). In those instances, Free'ing an already Free'd object will result in an EAccessViolation error and display an "error dialog". The same would also happen for the Assigned(Objects[I]) operation as well. If the object is Free'd, but the pointer is not nil'd afterwards, the condition will be fulfilled and you'll get an EAccessViolation error again.
0
 
LVL 8

Expert Comment

by:TOndrej
ID: 6485788
Hi malsoft,

I haven't looked at your code until now ;-)

> The loop in which the freeing is done
will continue to work

Which is IMHO wrong. The exception should not be suppressed.

> The loop in which the freeing is done
will continue to work even if one object has already been Free'd, but the pointer referencing it is
non-nil (which is normal for a Free operation).

If there is code that Frees objects referenced by the listbox items (which would be poor design, IMHO) then additional work is required to provide notification to the listbox to remove the item and reference.
Keeping invalid references doesn't make sense and is dangerous. So is your exception suppressing mechanism.

Just my 2c.
TOndrej
0
 
LVL 1

Expert Comment

by:malsoft
ID: 6485897
Hi TOndrej,

I said
> The loop in which the freeing is done
will continue to work

You said
>Which is IMHO wrong. The exception should not be suppressed.

However, you missed my point that you _can_ add whatever exception handling you want in there if you wanted to:

eg
  try
    // ...
  except
    on EAccessViolation do begin
      // handle already Free'd instances here
      end;
    on EException do
      // Everything else gets raised again
      raise;
  end;

As this code will be (normally) called within the context of the OnDestroy event, we need to ensure that the destruction completes, otherwise we end up with a memory leak (the remainder of the list will be skipped, leaving objects floating around in memory limbo).

You then said:
> If there is code that Frees objects referenced by the listbox items (which would be poor design, IMHO) then additional work is required to provide notification to the listbox to remove the item and reference.

This I would agree with, but as we do not know the nature of the objects that will be added to the list, some assumptions must be made. Here's an example for you: Say the objects added to the list were actual controls, created dynamically. To get them to display correctly, you need to assign them a Parent. When this Parent is notified of the Form's destruction, any child-control will also be destroyed at the same time (you don't call the Free method, the Parent tells all children to destroy themselves). When you come to do your own clean-up, you may try to Free the control you dynamically created and you will then get an EAccessViolation error because the object is already destroyed, but the reference to it is non-nil, hence Assigned() would still work and Free would attempt to re-Free the memory as it is not a nil value.

You said:
> Keeping invalid references doesn't make sense and is dangerous. So is your exception suppressing mechanism.

Keeping invalid references, I would whole-heartedly agree with. However, taking the above example into account, there's not much you can do about it. You either let the loop complete, freeing ALL objects, or you risk leaving some of the objects "floating around" inside the applications memory space when the unhandled exception jumps you out of the loop. In those occasions, the exception suppression is an asset rather than a liability.

I've not got any pennies to hand, but I've got a nickel! (that's inflation for you), so the tally stands at: 200pts and 7cents ;-)
0
 

Expert Comment

by:duti
ID: 6486020
Hi malsoft,

you got a point there, that the loop should continue. Even when one object could not be freed, the rest should at least be tried.  But using the 'assigned'-test, you can skip the exception-stuff and so make the code a little bit more readable. (if you are certain that uninitialized pointers will be nil)
And doing so, we use lesser keystrokes ;-)



Hi TOndrej,

TObject.Free might check if it is nil, the code never get that far, because 'Free' is a method of an object, and if the object itself is nil, the code will do an EAccessViolation before calling 'Free'.  I believe the procedure SysUtils.FreeAndNil would be more appropriate. (so it's shorter, readable, and saves even more keystrokes.)

But unfortunately the code
  FreeAndNil(ListBox1.items.Objects[1]);
won't compile. :(  
("Constant object cannot be passed as var parameter")

0
 
LVL 8

Expert Comment

by:TOndrej
ID: 6486716
duti,

> TObject.Free might check if it is nil, the code never
> get that far, because .... <snip>

try it:

var
  Obj: TObject;
begin
  Obj := nil;
  Obj.Free;
end;

> when one object could not be freed, the rest
should at least be tried
I disagree as I explained above.

malsoft,
> Parent tells all children to destroy themselves

and you need to get a notification of this so you can update your references...

> When you come to do your own clean-up, you may try
> to Free the control you dynamically created and you
> will then get an EAccessViolation error because the
> object is already destroyed

...exactly, to make sure this thing never happens.

> you risk leaving some of the objects "floating around" inside the applications memory space

Agreed. It seems to be a matter of taste. I prefer seeing all error messages. If there is an error in freeing an object, I want to know about it. I try to take enough precautions to never release code that would raise errors in object destruction; however if I do, I want the user to see it and hopefully report it, so I can fix it.

Cheers for an interesting discussion, and
Have a nice Delphi day :-)
TOndrej
0
 

Author Comment

by:NicoleKabitzki
ID: 6486744
Ok, that works! Thanx for your answer.

Bye
  Nicole
0

Featured Post

Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Introduction The parallel port is a very commonly known port, it was widely used to connect a printer to the PC, if you look at the back of your computer, for those who don't have newer computers, there will be a port with 25 pins and a small print…
Introduction Raise your hands if you were as upset with FireMonkey as I was when I discovered that there was no TListview.  I use TListView in almost all of my applications I've written, and I was not going to compromise by resorting to TStringGrid…
This is my first video review of Microsoft Bookings, I will be doing a part two with a bit more information, but wanted to get this out to you folks.
Have you created a query with information for a calendar? ... and then, abra-cadabra, the calendar is done?! I am going to show you how to make that happen. Visualize your data!  ... really see it To use the code to create a calendar from a q…
Suggested Courses

688 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question