PDA

View Full Version : destroy and data erasing



marmin
23-04-2007, 02:33 PM
Is it true that everything inside the Create section is automatically erased when calling the Destructor? I made a bunch of linked lists, but they're all part of TStage, so all the garbage that 's connected with that is erased from mem.
I create a Stage, destroy it, and then again create it with the same code.
But this time I get wierd errors. Like the 'new (XX);' statement gives an Acccess violation, when the first time not. It drives me crazy.
How can a 'New' statement give an acess violation?

Robert Kosek
23-04-2007, 02:40 PM
No, if you add new properties such as objects and arrays they aren't automatically destroyed. You must create a destructor, then after your own cleanup call the "inherited Destroy;".

marmin
23-04-2007, 02:46 PM
So I have to manually hand-clean ALL linked lists and other dynamic arrays that I made? Is the memory after the Destroy call not cleaned? That's awful.

marmin
23-04-2007, 04:39 PM
I manually erased the linked list.
But when I erase the list and call TStage.Free , I get an access violation. If I don't erase it, there's no access violation.. How can it be?

Are there detailed resources as to how the Free / Destroy method works? I don't understand what is freed and what not.

WILL
23-04-2007, 05:09 PM
I think the most difficult problems of OOP is the proper tracking and freeing up of loose Objects in your programs.

If you want to properly clean up all the allocated memory for objects that you don't use anymore, you have to destroy or Free everything. That means objects in objects, objects in arrays and anything that you basically had to NewObject := TObject.Create;

The good news is that you can use destructors inside destructors! So for your object that has other objects inside them you can create a new destructor function that will run the code nessissary to destroy all your other memory allocated bits inside.

Example:
destructor TGameObject.Free;
var
i: Integer;
begin
// Free each little beasty created!
for i := 0 to NumberOfGremlins - 1 do
Gremlins[i].Free;
end;

This also stands very true for objects within objects within objects. :) And so on...

JSoftware
23-04-2007, 10:34 PM
Doesn't the TObject implement nil checking of object before free'ing in it's Free procedure?

I always overload Destroy instead of free as free calls the overloaded destroy.

WILL
23-04-2007, 10:54 PM
Using Destroy is supposed to be more dangerous that Free.

iirc, Free is supposed to be able to check that the object is non nil before destroying the object where as destroy just does it regardless of it actually being allocated. In which case it would result in a memory error and your program would crash.

savage
23-04-2007, 11:12 PM
He means your code should have read...

destructor TGameObject.Destroy;
var
i: Integer;
begin
// Free each little beasty created!
for i := 0 to NumberOfGremlins - 1 do
Gremlins[i].Free;
inherited;
end;

Note it is very important that you call inherited in your destructor to ensure correct destruction of all parent classes.

Robert Kosek
24-04-2007, 12:42 AM
Anything created or allocated must be manually freed; objects, arrays, arrays of objects, and records (especially if they contain the previous) for good form.


type
TThingy = class
private
fArray: array of integer;
procedure DoSomethingIrritating;
public
destructor Destroy; override;
constructor Create;
end;

{...}

destructor TThingy.Destroy;
begin
setlength(fArray,0);
inherited Destroy;
end;

constructor TThingy.Create;
var i: integer;
begin
setlength(fArray,100);
for i := 0 to 100 do
fArray[i] := random(1000000);
end;

procedure TThingy.DoSomethingIrritating;
begin
for i := 0 to 5 do
if random() > 0.5 then
fArray[high(fArray)] := pwr(random(90)+10,random(6)+1);

if random() > 0.3 then
DoSomethingIrritating;
end;

Don't override MyObject.Free ever. Only override the destroy destructor and Delphi/FPC/Lazarus will do the rest. The point is, just override the descendant function and then call the parent one. Free isn't a function intended to be overridden, and was written to do a few things and then call the destroy event.

In your code you should call free, but in designing an object you should override destroy. Any further questions?

(This is pseudocode written in the browser, so don't blame me if it doesn't work. I haven't touched Delphi in 45 days.)

Dan
24-04-2007, 03:29 AM
(This is pseudocode written in the browser, so don't blame me if it doesn't work. I haven't touched Delphi in 45 days.)
Just one important note:
You must put override at the end of the destructor declaration, like this:
TThingy = class
private
fArray: array of integer;
procedure DoSomethingIrritating;
public
destructor Destroy; override;
constructor Create;
end;

savage
24-04-2007, 07:18 AM
I've edited Robert's post to reflect the override; change, so that any newbies looking at the code can see what is the correct thing to do.

marmin
24-04-2007, 09:57 AM
Anything created or allocated must be manually freed; objects, arrays, arrays of objects, and records (especially if they contain the previous) for good form.
In your code you should call free, but in designing an object you should override destroy. Any further questions?
No, I understand, but I've a huge amount of dyn. arrays and lists, and I figured it would be very nice if the compiler could 'free' them automatically. In theory that could work.

Robert Kosek
24-04-2007, 10:28 AM
Thanks guys, I forgot that one little tag. :)

In theory sure, and this is what things like C# and Java do: garbage collection. Though, sometimes you want to leave that memory allocated, and so have to work around the language. Pascal at least gives you the option, though it requires you to do most your own cleanup. Though I must admit pascal even makes that easy.

savage
24-04-2007, 01:21 PM
No, I understand, but I've a huge amount of dyn. arrays and lists, and I figured it would be very nice if the compiler could 'free' them automatically. In theory that could work.

But the question is, when should it free then automatically? If you have created the object within your code, when does the compiler know, except when the application is shutting down? Any other scenario would require a garbage collector.

Garbage collectors check and decide when something goes out of scope, but that is where some of the speed is lost because a background thread is always looking for unused objects.

marmin
24-04-2007, 01:58 PM
Well, everything that is created inside the constructor, is freed inside the destructor. If I call x.Destroy .The compiler has made a list (when calling x.Create) what dyn. arrays or pointers were created, and erases these. Of course, this problem arises because i'm purist and like to torture me with home-made linked lists. But.. compiler can do it. It should keep track what arrays etc. are made inside create and free it when called destructor. :D

savage
24-04-2007, 02:22 PM
What happens in the case where your create an object inside one class, but it is used in some other class? For example a factory pattern only tends to create objects, while other classes may use those objects. Will the compiler know then when it should be freed?

marmin
24-04-2007, 02:35 PM
Afaik when an object is destroyed it doesn't exist anymore so it can't be used.. if there is a reference to that object in some other object then that object should take care not to use the 1st object.. this is not an oop issue but simply teh compiler has an extra job to do..

jdarling
24-04-2007, 04:05 PM
Marmin thats called interfaced objects, and to answer savages point thats why we have messages and listener queues :). FPC and Delphi are not Garbage collection languages, due to Chrome you can't say that Pascal isn't a GC'd language in general :).

Some factory objects to maintain the children that they produce. For example JumpStart uses a factory to create and manage all objects utilized within the game. Each object has a Lua reference that says if Lua is utilizing the object as well. When the Lua Garbage Collector is called the objects are only freed if they are not in use some place else. When they fall out of use completely the factory cleans up (effectively producing a true garbage collection system within FPC).

Of course, the fun part is deciding when an object is in use :).

Setharian
25-04-2007, 05:26 AM
Anything created or allocated must be manually freed; objects, arrays, arrays of objects, and records (especially if they contain the previous) for good form.


destructor TThingy.Destroy;
begin
setlength(fArray,0);
inherited Destroy;
end;

Don't override MyObject.Free ever. Only override the destroy destructor and Delphi/FPC/Lazarus will do the rest. The point is, just override the descendant function and then call the parent one. Free isn't a function intended to be overridden, and was written to do a few things and then call the destroy event.
not exactly true....everything allocated manually that is using GetMem/AllocMem/New or other forms of manual memory allocation (OS API)....dynamic arrays, interfaces, strings are reference counted and thus you do not need to free them explicitly....if you create dynamic arrays of pointers or classes (which are actually pointers) then you have to deallocate elements explicitly (if you want to), but the array is automaticly deleted once its reference count reaches zero.....so the line "SetLength(fArray, 0)" is not needed...as a side note, .Free is not virtual so you cannot override it....

jdarling
25-04-2007, 01:13 PM
Define overriding it. You can certainly reintroduce free as a procedure and it will be called instead of the default one. You can then do an inherited free within your reintroduced version that will call the original. So saying that you can't override it is incorrect :). Granted you can't use the override keyword to achieve it, but the end result is the same.

Setharian
25-04-2007, 04:08 PM
You can certainly reintroduce free as a procedure and it will be called instead of the default one.
that will work only when you'd call .Free on a variable of the type which hides or reintroduces the method...calling FreeAndNil for example would invoke the correct original .Free method.....but yes, it is a form of overriding :)