TStringlist as function result, minimal code sequence

 

How to return a Stringlist from a function has been discussed many time before. My code sequence version 1 is just a recap how to do it.

function GetStrings : TStringList;
begin
  Result := TStringList.Create;
  Result.Add('string A');
  Result.Add('string B');
end;

procedure TForm1.Button1Click(Sender: TObject);
var stemp : tStringList;
begin
  stemp := GetStrings;
  MyListBox.items.addstrings(stemp);
  stemp.Free;
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
  MyListBox.items.addstrings(GetStrings);
end;

is there any option to fix the memory leak in version2 with "no extra code", how dangerous is this approach at all, will this cause any failures if my stringlist is just a few string items, out of memory issues will not happen?


---------------------------------------------------------------------------------------------------------------


As others as mentioned, you need to add extra code to both the function and the caller in order to manage the TStringList correctly to ensure it is always freed.

A better option is to not return a TStringList at all, but rather to take in any TStrings object the caller wants and just fill it in, eg:

procedure GetStrings(Strings: TStrings);
begin
  Strings.BeginUpdate;
  try
    Strings.Add('string A');
    Strings.Add('string B');
  finally
    Strings.EndUpdate;
  end;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  GetStrings(MyListBox.Items);
end;

--------------------------------------------------------------------------------------------------------------------------------------

If you are going to return a newly instantiated object from a function, there is a pattern for that. It goes like this:

function GetStrings: TStringList;
begin
  Result := TStringList.Create;
  try
    Result.Add('string A');
    Result.Add('string B');
  except
    Result.Free;
    raise;
  end;
end;



This function behaves just like a constructor. Either it returns a newly instantiated object, and passes ownership to the caller. Or it raises an exception, and tidies up before raising it.

If you use this pattern, then you need to do so in the same way as you would with an object instantiated by a constructor, using the well known pattern:

procedure TForm1.Button1Click(Sender: TObject);
var 
  temp: TStringList;
begin
  temp := GetStrings;
  try
    MyListBox.Items.AddStrings(temp);
  finally
    temp.Free;
  end;
end;

Now, as for your direct question:

is there any option to fix the memory leak in version2 with "no extra code", how dangerous is this approach at all, will this cause any failures if my stringlist is just a few string items, out of memory issues will not happen?

If you do return a newly instantiated object, then the caller can't avoid the responsibilities of ownership for that object.



Learn more about this article kindly follow this link