[fpc-pascal] memory management with open arrays and classes

Jonas Maebe jonas.maebe at elis.ugent.be
Thu Jun 26 20:19:40 CEST 2008


On 23 Jun 2008, at 11:21, Joost van der Sluis wrote:

> Op zaterdag 21-06-2008 om 19:23 uur [tijdzone -0700], schreef David
> Emerson:
>
>> 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?)
>
> After calling setlength, the items in the array are not initialised.

That's incorrect, the array is set to 0. Also, note: this discussion  
is about dynamic arrays, not about open arrays. These are two  
completely different beasts.

> Note that in the pascal language allocated memory is never
> initialised/set to 0. The only exceptions are the variables in  
> classes.
> (There are some functions that allocate memory and initialise is
> afterwards explicitely, see the documentation)

And except in cases when you work with reference counted types (such  
as ansistrings and the dynamic arrays themselves (i.e., the pointers  
to the dynamic arrays)). And contents of dynamic arrays (regardless of  
the element type) are also an exception.

> Initialising the strings you can do by setting them to an empty  
> string.
> (:= '')

Ansistrings never need to be explicitly initialised to '', that's  
their default value.

>> 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?
>
> You can expect this, but I woudn't know.

It does clean up everything (and this is guaranteed).

>> 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);
>
> Yup, it's pretty consistent.

You have to call Free, not Destroy. And in this case you indeed do  
have to free the instances, because classes are not reference counted  
(unlike ansistrings) and hence not freed automatically (since you may  
still have pointers to these references elsewhere).

>> 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?
>
> Yes
>
>>   for i := 0 to high(str_arr_arr) do setlength (str_arr_arr[i], 0);
>>   // or will setlength silently do the job anyway?
>
> No

Yes, it will. The reason is that dynamic arrays are reference counted  
and hence properly finalized to the full extent that is necessary.
>> 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?
>
> The setlengths to 0 aren't needed.

Setting the ansistrings to '' isn't either, so it indeed does not do  
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?
>
> Not if you do not have a create that creates embedded_cls. But  
> normally:
> yes.

Correct, except that you have to call .Free rather than .Destroy.


Jonas



More information about the fpc-pascal mailing list