Question

Consider this short Delphi procedure:

procedure TfrmXQuery.FieldListFillFromDefault;
var
  field_list: TStringList;
begin
  try
    if x <> '' then begin
      field_list := TStringList.Create;
      {do some stuff with field_list}
    end;
  finally
    if field_list <> NIL then 
    begin
      field_list.Free;
    end;
  end;
end;

When I run this in, Delphi 3, with x = '' so that field_list is never created,

  1. why is field_list <> NIL?
  2. are objects not initialized as NIL?
  3. if it's not NIL what is it?
  4. and if it's unassigned and not NIL how do I know whether or not to Free it? The Assigned function does not tell me: if Assigned(an_object) is equivalent to if an_object = NIL
Was it helpful?

Solution 2

Answers to the questions:

  1. why is field_list <> NIL? Delphi does not initialize local objects. For more details see: Why doesn't object default to nil? and Are delphi variables initialized with a value by default?

  2. are objects not initialized as NIL? Global objects: Yes. Local objects: No.

  3. if it's not NIL what is it? Invalid pointers.

  4. and if it's unassigned and not NIL how do I know whether or not to Free it? You need to reorganize your code (see below). The Assigned function does not tell me: if Assigned(an_object) is equivalent to if an_object = NIL. Assigned tests for a nil (unassigned) pointer or procedural variable. <--from Delphi 3 documentation. Uninitialized local objects are not assigned NIL so Assigned(an_object) returns TRUE if an_object is local and has never been used (assigning NIL is using the object).

Because objects local to a procedure are not initialized to NIL, I have revised the code from the question assigning all local objects that are local to NIL. I do these assignments at the very beginning of the routine so that Free will not error out if the local objects are never created. I've also shown the error tracking code that was left out of the original question:

procedure TfrmXQuery.FieldListFillFromDefault;
var
  field_list: TStringList;
  some_other_object: TAnotherObject;
begin
  try
    try
      field_list := NIL;
      some_other_object := NIL;
      if x <> '' then begin
        field_list := TStringList.Create;
        {do some stuff with field_list}
      end;
      {...}
      some_other_object := TSomeOtherObject.Create;
      {...}
    except
      On E : Exception do begin
        ErrorTrackingRoutine(unit_name, name, 'FieldListFillFromDefault', E.message);
      end;
    end;
  finaly
    field_list.Free;
    some_other_object.Free;
  end;
end;

The entire routine is protected by try...except. If field_list or some_other_object are created it will be freed. They are assigned NIL at the very beginning so freeing them in the 'try...finally` block will not raise an error even if there is a run time error before they are created.

OTHER TIPS

The problem is that if x = '', the finally happens anyway. Since field_list is only initialized when x <> '', it's a random memory location before that point, because it's an uninitialized local variable. The random value allows the field_list.free to be called, because it's not equal to nil. (Delphi doesn't initialize local variables (those declared within a function or procedure).)

var
  somevar: sometype;    
begin
  // at this point, somevar is just a chunk of memory that
  // holds whatever happens to be in that chunk
  somevar := nil;         // now somevar = a specific value you can test

  // other code
end;

You shouldn't have to test for <> nil (as others have pointed out in comments) if you structure your code correctly.

procedure TfrmXQuery.FieldListFillFromDefault;
var
  field_list  : TStringList;
begin
  if x <> '' then 
  begin
    field_list := TStringList.Create;
    try
      {do some stuff with field_list}
    finally
      field_list.Free;
    end;
  end;
end;

(If you turn on hints and warnings, the compiler would have told you that field_list may not have been initialized, which would have helped you solve this yourself.)

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top