[fpc-pascal] memory management with open arrays and classes
David Emerson
dle3ab at angelbase.com
Sun Jun 22 04:23:04 CEST 2008
Hi all,
I'm pretty new to both "open arrays" and OOP, and am feeling a bit
concerned about memory management and leaks in my code. I will jump
straight into examples and questions:
type
T_my_object = object (TObject)
{...}
end;
T_my_class = class (TComponent)
{...}
end;
type
str_array_type = array of ansistring;
int_array_type = array of integer;
obj_array_type = array of T_my_object;
cls_array_type = array of T_my_class;
var
str_arr : str_array_type;
int_arr : int_array_type;
obj_arr : obj_array_type;
cls_arr : cls_array_type;
begin
{...}
setlength(str_arr, some_maximum);
setlength(int_arr, some_maximum);
setlength(obj_arr, some_maximum);
setlength(cls_arr, some_maximum);
{...}
First: what does setlength do about initialization? There are a couple
different cases here...
1. If the setlength function is creating an array of things which happen
to be stored as pointers (ansistrings in str_arr or class instances in
cls_arr) then will the pointers be initialized to nil by setlength? Or
do I need to manually initialize all pointers to nil, after calling
setlength? (I guess for ansistrings that would require using
fillchar ... but maybe setlength is already doing this?)
2. Of course the primary concern is cleaning up. For the ansistring
case, can I simply call:
setlength (str_arr, 0);
...and expect that the ansistring references will be properly
decremented and cleaned up?
Or do I need to explicitly clear them myself?
for i := 0 to high(str_arr) do str_arr[i] := '';
setlength(str_arr, 0);
3. Similarly for the cls_arr, do I need to explicitly call the
destructor?
for i := 0 to high(cls_arr) do
if cls_arr[i] <> nil then cls_arr[i].Destroy;
setlength(cls_arr, 0);
...or will setlength call the destructor when the array is shrunk?
(Assumably only for non-nil pointers :)
As for the other types... for int_arr it must be a non-issue, and for
obj_arr ... objects DO need to be destroyed! Although this is only a
matter of curiousity, since I'm not using any objects that aren't
classes
And of course the "array in array" example comes to mind:
var
str_arr_arr : array of str_arr;
begin
setlength (str_arr_arr, 5);
setlength (str_arr_arr[3], 17);
{...}
// is it necessary to free all of the members as seen below?
for i := 0 to high(str_arr_arr) do setlength (str_arr_arr[i], 0);
// or will setlength silently do the job anyway?
setlength (str_arr_arr, 0);
Conversely, do open arrays get automatically cleaned up as part of an
object destruction, or do I need to write that into the destructor?
type
T_my_other_class = class (TComponent)
private
str_arr : str_array_type;
int_arr : int_array_type;
cls_arr : cls_array_type;
public
constructor Create (my_owner : TComponent; pass_size :
integer); override;
destructor Destroy;
end;
constructor T_my_other_class.Create (my_owner : TComponent; pass_size :
integer);
begin
inherited Create (my_owner);
setlength (str_arr, pass_size);
setlength (int_arr, pass_size);
end;
destructor T_my_other_class.Destroy;
begin
for i := 0 to high(str_arr) do str_arr[i] := ''; // again :)
setlength (str_arr, 0);
setlength (int_arr, 0);
// and what about cls_arr, even more messy of course :)
inherited Destroy;
end;
4. Is the above destructor actually doing anything that doesn't happen
automatically?
And the last case, objects embedded in objects:
type
T_my_third_class = class (TComponent)
embedded_cls : T_my_other_class;
bool_arr : bool_array_type;
{...}
end;
5. Do I need to override the destructor with one that explicitly calls
embedded_cls.Destroy?
Of course, I didn't ask until I was already knee-deep in several layers
of this stuff...
type
third_class_array_type = array of T_my_third_class;
T_group_array = class(TComponent)
third_arr : third_class_array_type
{...}
end;
var
g_arr : array of T_group_array;
... and so on. Actually, I think that's as many layers as I've got!
whew.
Happily the program runs! I am doing a lot of this cleanup manually,
though, and am now wondering if I should cut some of my cleanup code
out as extraneous, or if I rather need to triple-check it and perhaps
reinforce it with yet more cleanup code.
Thanks!
~David.
More information about the fpc-pascal
mailing list