reynaerde
asked on
destructor - override: memory management(again)
So, this is basically a follow up to another question I posted earlier about memory management.
Consider the following classes:
TCell = class(TObject)
status : cell_status;
nA1, nA2 : integer;
strand: integer;
to_update : cell_status;
lifetime: integer;
resist: integer;
activated: bool;
constructor create();
end;
TMargolusBlock = class(TObject)
cell : array[0..3] of TCell;
cellCountH, cellCountA1, cellCountA2, cellCountA3, cellCountD : integer;
LatticeReference1, LatticeReference2 : Integer;
constructor create(cell0,cell1,cell2,c ell3 : TCell);
//destructor Destroy;
// override;
end;
TMargolusArray = class(TObject)
mblock : array of array of TMargolusBlock;
constructor create(size : Integer);
destructor Destroy;
override;
end;
These are the constructors:
constructor TMargolusBlock.create(cell 0,cell1,ce ll2,cell3 : TCell);
begin
self.cell[0] := cell0;
self.cell[1] := cell1;
self.cell[2] := cell2;
self.cell[3] := cell3;
self.cellCountH := 0;
self.cellCountA1 := 0;
self.cellCountA2 := 0;
self.cellCountA3 := 0;
self.cellCountD := 0;
end;
constructor TMargolusArray.create(size : Integer);
begin
setlength(mblock, size+1, size+1);
end;
Now, I tried using a custom destructor:
When I only use the second one it works(I think, I have some suspicions about memory usage/leakage)
but when I add the first one (Destructor TMargolusblock.Destroy) I get an error
Can anyone explain this to me?
{*
Destructor TMargolusblock.Destroy;
var
Teller1 : Integer;
begin
for Teller1 := 0 to 3 do
begin
cell[Teller1].Free();
end;
inherited destroy;
end;
*}
Destructor TMargolusArray.Destroy;
var
Teller1, Teller2 : Integer;
begin
for Teller1 := low(mblock[0]) to high(mblock[0]) do
begin
for Teller2 := low(mblock[0]) to high(mblock[0]) do
begin
mblock[Teller1, Teller2].Free();
end;
end;
inherited destroy;
end;
This is when using another procedure to fill the MargolusArray.
After some debugging/testing I also noticed that this gives an error(related I guess):
constructor TMargolusArray.create(size : Integer);
var
Teller1, Teller2 : Integer;
empty_cell : TCell;
empty_margolus : TMargolusBlock;
begin
setlength(mblock, size+1, size+1);
empty_cell := TCell.create;
empty_margolus := TMargolusBlock.create(empt y_cell,emp ty_cell,em pty_cell,e mpty_cell) ;
for Teller1 := 0 to size do
begin
for Teller2 := 0 to size do
begin
mblock[Teller1, Teller2] := empty_margolus;
end;
end;
Or even:
mblock[5,5] := empty_margolus;
mblock[5,6] := empty_margolus;
end;
I thought the mblock[index1,index2] was just a pointer to the empty_margolus memory location..?
Hope someone can explain it to me :)
Consider the following classes:
TCell = class(TObject)
status : cell_status;
nA1, nA2 : integer;
strand: integer;
to_update : cell_status;
lifetime: integer;
resist: integer;
activated: bool;
constructor create();
end;
TMargolusBlock = class(TObject)
cell : array[0..3] of TCell;
cellCountH, cellCountA1, cellCountA2, cellCountA3, cellCountD : integer;
LatticeReference1, LatticeReference2 : Integer;
constructor create(cell0,cell1,cell2,c
//destructor Destroy;
// override;
end;
TMargolusArray = class(TObject)
mblock : array of array of TMargolusBlock;
constructor create(size : Integer);
destructor Destroy;
override;
end;
These are the constructors:
constructor TMargolusBlock.create(cell
begin
self.cell[0] := cell0;
self.cell[1] := cell1;
self.cell[2] := cell2;
self.cell[3] := cell3;
self.cellCountH := 0;
self.cellCountA1 := 0;
self.cellCountA2 := 0;
self.cellCountA3 := 0;
self.cellCountD := 0;
end;
constructor TMargolusArray.create(size
begin
setlength(mblock, size+1, size+1);
end;
Now, I tried using a custom destructor:
When I only use the second one it works(I think, I have some suspicions about memory usage/leakage)
but when I add the first one (Destructor TMargolusblock.Destroy) I get an error
Can anyone explain this to me?
{*
Destructor TMargolusblock.Destroy;
var
Teller1 : Integer;
begin
for Teller1 := 0 to 3 do
begin
cell[Teller1].Free();
end;
inherited destroy;
end;
*}
Destructor TMargolusArray.Destroy;
var
Teller1, Teller2 : Integer;
begin
for Teller1 := low(mblock[0]) to high(mblock[0]) do
begin
for Teller2 := low(mblock[0]) to high(mblock[0]) do
begin
mblock[Teller1, Teller2].Free();
end;
end;
inherited destroy;
end;
This is when using another procedure to fill the MargolusArray.
After some debugging/testing I also noticed that this gives an error(related I guess):
constructor TMargolusArray.create(size
var
Teller1, Teller2 : Integer;
empty_cell : TCell;
empty_margolus : TMargolusBlock;
begin
setlength(mblock, size+1, size+1);
empty_cell := TCell.create;
empty_margolus := TMargolusBlock.create(empt
for Teller1 := 0 to size do
begin
for Teller2 := 0 to size do
begin
mblock[Teller1, Teller2] := empty_margolus;
end;
end;
Or even:
mblock[5,5] := empty_margolus;
mblock[5,6] := empty_margolus;
end;
I thought the mblock[index1,index2] was just a pointer to the empty_margolus memory location..?
Hope someone can explain it to me :)
SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
@geobul, nope... Wrong :-P
If the base class is TObject then technically the only thing the inherited constructor does is zero the instance memory before it's used. Still, it is a very good idea to call the inherited Create method since it initializes data that you might need. It's just a bit sloppy if you don't...
If the base class is TObject then technically the only thing the inherited constructor does is zero the instance memory before it's used. Still, it is a very good idea to call the inherited Create method since it initializes data that you might need. It's just a bit sloppy if you don't...
I'd use:
Destructor TMargolusblock.Destroy;
var
Teller1 : Integer;
begin
for Teller1 := 3 downto 0 do
begin
cell[Teller1].Free();
end;
inherited destroy;
end;
Regards, Geo
Destructor TMargolusblock.Destroy;
var
Teller1 : Integer;
begin
for Teller1 := 3 downto 0 do
begin
cell[Teller1].Free();
end;
inherited destroy;
end;
Regards, Geo
I had in mind:
Destructor TMargolusblock.Destroy;
var
Teller1 : Integer;
begin
for Teller1 := 3 downto 0 do
begin
cell[Teller1] := nil; // not Free
end;
inherited destroy;
end;
Sorry.
Destructor TMargolusblock.Destroy;
var
Teller1 : Integer;
begin
for Teller1 := 3 downto 0 do
begin
cell[Teller1] := nil; // not Free
end;
inherited destroy;
end;
Sorry.
ASKER
Ok, but:
- I thought free() checks for nil reference anyway
- Why can't I assign two variables pointing at the same object?
constructor TMargolusArray.create(size : Integer);
var
empty_cell : TCell;
empty_margolus : TMargolusBlock;
begin
setlength(mblock, size+1, size+1);
empty_margolus := TMargolusBlock.create(TCel l.create,T Cell.creat e,TCell.cr eate,TCell .create);
mblock[5,5] := empty_margolus;
mblock[5,6] := empty_margolus;
end;
This code gives me an error, WITHOUT using any destructor..
- I thought free() checks for nil reference anyway
- Why can't I assign two variables pointing at the same object?
constructor TMargolusArray.create(size
var
empty_cell : TCell;
empty_margolus : TMargolusBlock;
begin
setlength(mblock, size+1, size+1);
empty_margolus := TMargolusBlock.create(TCel
mblock[5,5] := empty_margolus;
mblock[5,6] := empty_margolus;
end;
This code gives me an error, WITHOUT using any destructor..
ASKER
I'm sorry, I stand corrected on the last point, there was another error in my code causing the error.
SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
That is more or less what I'm trying to do, only the problem is:
* I need to be able to have different cells in the MargolusBlock point to the same cell AND free the memory afterwards..
For example, in my program I will have:
(not real code, just to give an idea)
MA1, MA2 : TMargolusArray;
cellA : TCell;
where:
cellA := TCell.create();
MA1 := TMargolusArray.create(10);
MA2 := TMargolusArray.create(10);
MA1.mblock[1, 2] := TMargolusBlock.create(cell A,cellX1,c ellX2,cell X3);
MA2.mblock[2, 2] := TMargolusBlock.create(cell A,cellY1,c ellY2,cell Y3);
Using this constructor:
constructor TMargolusBlock.create(cell 0,cell1,ce ll2,cell3 : TCell);
begin
self.cell[0] := cell0;
self.cell[1] := cell1;
self.cell[2] := cell2;
self.cell[3] := cell3;
self.cellCountH := 0;
self.cellCountA1 := 0;
self.cellCountA2 := 0;
self.cellCountA3 := 0;
self.cellCountD := 0;
end;
So, instead of creating a new TCell, I'm just referencing an already existing TCell.
The assignment part works fine, only when it comes to freeing it afterwards I run into problems..
Is there any way to have this working? Or should I really make a copy of each TCell?? This would mean a LOT of extra work since I'm accessing the TCells through a number of different Objects(not just TMargolusArrays, but also TLattice, another class which has an array of cells in it)
Thanks a bunch in advance!
* I need to be able to have different cells in the MargolusBlock point to the same cell AND free the memory afterwards..
For example, in my program I will have:
(not real code, just to give an idea)
MA1, MA2 : TMargolusArray;
cellA : TCell;
where:
cellA := TCell.create();
MA1 := TMargolusArray.create(10);
MA2 := TMargolusArray.create(10);
MA1.mblock[1, 2] := TMargolusBlock.create(cell
MA2.mblock[2, 2] := TMargolusBlock.create(cell
Using this constructor:
constructor TMargolusBlock.create(cell
begin
self.cell[0] := cell0;
self.cell[1] := cell1;
self.cell[2] := cell2;
self.cell[3] := cell3;
self.cellCountH := 0;
self.cellCountA1 := 0;
self.cellCountA2 := 0;
self.cellCountA3 := 0;
self.cellCountD := 0;
end;
So, instead of creating a new TCell, I'm just referencing an already existing TCell.
The assignment part works fine, only when it comes to freeing it afterwards I run into problems..
Is there any way to have this working? Or should I really make a copy of each TCell?? This would mean a LOT of extra work since I'm accessing the TCells through a number of different Objects(not just TMargolusArrays, but also TLattice, another class which has an array of cells in it)
Thanks a bunch in advance!
SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
Well, I finally managed to bring my memory leak down from something like 20MB/100 iterations to around 10 bytes. Still not perfect but good enough for me. I still don't feel I really understand the different aspects of memory management but certainly feel I have a better grasp.
So, thank you both a lot. I hope you feel the division of points is a fair one.
Thanks again!
So, thank you both a lot. I hope you feel the division of points is a fair one.
Thanks again!
When you are defining a constructor you have to call 'inherited Create' as a first command in the constructor:
constructor TMargolusArray.create(size
begin
inherited Create;
setlength(mblock, size+1, size+1);
end;
Regards, Geo