views:

602

answers:

5

When an object that is created within a function and the function is completed, what happens to the object if it wasn't explicitly destroyed?

Do all variables need to be destroyed when they fall out of scope or are they taken care of when they fall out of scope?

So for example, what happens to locallist after custom_function has been called?

function TForm1.custom_function(string: test_string): boolean;
var locallist: TStringList;
begin
  locallist := TStringList.Create;
  // do a bunch of stuff here, but don't destroy locallist
  return true;
end;
+4  A: 

It becomes leaked memory.

You should typically surround such allocations thus:

locallist := TStringList.Create;
try
     // work with locallist here
  finally
     locallist.Free;
  end;

The only kind of references in Delphi that are suicidal when they drop out of scope are interface references.

Jim
and string references and interfaces references
Barry Kelly
The create comes before the try. Always.
Ray
If you use this, you will get warnings for each object, as it's possible the create will fail, and the object will then attempt to be freed.
Ray
If you set localList := nil first then you won't get the warning. If you are creating multiple objects at once then that is the preferred pattern.
Jim McKeeth
Serves me right for typing so quickly and not re-reading. Like I don't use this pattern dozens of times every day <sigh>. I edited my response to move the creation outside the try, where it belongs.
Jim
+3  A: 

The memory is not reclaimed, sorry. You need to explicitly free this object using locallist.Free;

+3  A: 

This will result in a memory leak that will only be destroyed at the end of the application. To detect those, you can use a memory manager like FastMM.

Note that you can destroy objects either using the Destroy or the Free method. The first will give an error if the object is nil, the latter won't - it is equal to

if Assigned(Object) then Object.Destroy;
schnaader
So is that FastMM tool something that is compiled into the app or is it some type of add-on to the Delphi editor/compiler?
Dave
It is compiled into the app. You add it to the uses clauses and it gets added to your project. It has two effects: 1. Speeding up Delphi memory routines, 2. Detecting memory leaks. Memory leaks are reported with a stack trace when the project is run in the compiler.
schnaader
I thought FastMM was incorporated into the later Delphi versions (well the speeding up part anyway). I could be wrong.
Ray
Most of FastMM is incorporated into the last few Delphi versions, but there's a more feature-rich version at http://sourceforge.net/projects/fastmm/ with extra options to help with debugging.
Mason Wheeler
That should be if Assigned(Object) then Object.Destroy; Otherwise it would recurse!
Gerry
No need to check if Object is assigned. The Free method does that for you.
dangph
Oops, corrected.
schnaader
+14  A: 

You will get a memory leak.

The proper pattern is

myObject := TObject.Create;
try
  //do stuff
finally
  myObject.Free;
end;

Also if you need to test later if the object has been freed, then use FreeAndNil(myObject). It will set the variable to nil as well, so you can test it later.

Ray
+8  A: 

As the other posters noted, these objects need to be explicitly freed. This is usually done manually by the use of a try..finally block, as Ray demonstrated. There are exceptions, though, that you ought to be aware of.

Components (TComponent descendants) pass an Owner parameter to their constructor. If the owner is not nil, then the owner component will take ownership of the new component and free it when it gets freed. This is why you don't have to clean up your own forms; they're connected to the Application object, which knows how to free itself when the program's finished. However, if you create a component at runtime, you need to either assign it an owner or pass nil to the constructor and then free it yourself. Do not mix the two by freeing a component with an owner. That can cause a double-free condition under certain circumstances.

Interfaced objects that implement reference counting (TInterfacedObject descendants, mostly) are freed by the reference counting mechanism if you refer to them specifically as an interface (not as an object.) They get freed automatically when the last interface reference to them is removed. Don't free a TInterfacedObject manually if you've already assigned it to an interface reference. This will raise an exception. Also, be aware that not all objects with interfaces implement reference counting. Mostly just the ones that are descended from TInterfacedObject.

It's not always practical to create an object, use a try..finally block, and then free it. Sometimes that just doesn't work for what you're doing, especially if you're assigning the object to some sort of list (and making a whole lot of them.) In that case, it's a good idea to use a TObjectList (or better still, if you have D2009, a TObjectList) with the OwnsObjects property set to true. This causes the list to become the owner of the objects in it and free them when it gets freed, just like components do. Again, don't free an object manually if it's owned by an object list.

Dynamic arrays (including strings) are managed by the compiler with a reference-counting system, and most other types of variables are allocated on the stack. You never have to worry about manually freeing anything other than objects, unless you're playing around with pointers.

This probably sounds complicated, but you'll get used to it soon enough. Just remember that every object is owned by one of three things: another object, the interface reference-counting system, or your code, and the owner should free all of its objects when they're no longer needed. Nothing should try to free something that's owned by something else. (Thou shalt not steal.) Remember these guidelines and you'll end up with good memory management. You can also set "ReportMemoryLeaksOnShutdown := true" in the main routine in your DPR for a bit more help.

Mason Wheeler
"Do not mix the two by freeing a component with an owner. That will cause a double-free condition." Can we please stop repeating this? It's simply wrong. Freeing a component with an owner will remove it from the list of owned components the owner maintains. It may be suboptimal, or confusing, ...
mghie
but it's not wrong or dangerous. For more information see http://stackoverflow.com/questions/398137. This subtracts from your otherwise good answer.
mghie
Depends on how it's done. This one bit me once when I had code that tried to free a component I'd created *after* the form that owned it had been destroyed. (Yes, that's not a common condition, but it can happen if you're not careful.) But I'll edit it a bit...
Mason Wheeler
Basically, it's like modifying an array/list in the middle of a for loop that iterates over it. It's usually safe, but it can be dangerous if you're not careful, and you're better off just not doing it.
Mason Wheeler
@Mason: Your reason doesn't convince me at all. By that rationale one should discourage pointer use at all, because there's always the possibility that one could dereference them after the pointees have been destroyed. And your "edit" thus amounts to saying: "Do not use pointers, because that ...
mghie
can lead to access violations under certain circumstances." It's basically meaningless.
mghie
Another case in point: "Do not mix the two by freeing a component with an owner" means that you may never a) call Form.Free b) call Form.Release c) set Action to caFree in Form.OnClose if the form has an owner. You will agree that this isn't a reasonable point of view.
mghie
Calling Form.Free is usually a bad idea if you didn't create the form dynamically. The Release and caFree techniques, though, are designed specifically to allow the form to clean itself up safely. Nothing wrong with those two.
Mason Wheeler
Well, which is it then - "do not free a component with an owner", or "nothing wrong with those two"? You can't have it both ways, the form has an owner.
mghie
caFree just changes the normal behavior of TForm.Close. It's safe. TForm.Release is a free that allow form to finish message-queue and other processing before going into the destruction process. Both are tailored to the case in hand.. Mason's is more a general rule and I already do that (if I create a form to destroy before the Application does, it have a nil owner).
Fabricio Araujo