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
_______________________________________________
fpc-pascal maillist  -  fpc-pascal@lists.freepascal.org
http://lists.freepascal.org/mailman/listinfo/fpc-pascal

Reply via email to