I have a delphi function that returns a TStringList, but when I return a value and try to use it I get a Access Violation Error i.e
myStringList := FuncStringLis
You simply cannot free something and then expect to reference it later. That is the wrong way. You have two basic options:
The first option seems simpler, keeps the interface to the function smaller, etc. The second option makes usage less error prone because it's intuitive to the caller that it's responsible for managing the object.
both are reffering to same memory,if you free it both will get freed.......
Simple answer (with examples):
When you do
Result := vStrList
you assign vStrList to Result. At this moment vStrList and Result ARE THE SAME THING! So, in the next line of code, when you free vStrList, you free also Result (well, this is not TECHNICALLY accurate but I used it to keep the explanation simple). This is why you get an AV when you try to use the result of the function. The Result was destroyed when you freed vStrList.
So, this will solve your problem:
function FuncStringList:TStringList;
begin
Result := TStringList.Create;
// Do stuff with Result
// never free (here, in this function) the Result
end;
The caller of FuncStringList will HAVE TO free "Result".
You call it like this:
myStringList := FuncStringList;
try
myStringList.Items.Count
finally
FreeAndNil(myStringList); <------------- NOW you can free "Result"
end;
.
Another example:
function makelist: tstringlist;
begin
result := Tstringlist.create;
result.add('1');
result.add('2');
end;
procedure TForm1.Button_GOOD_Click(Sender: TObject);
var list : tstringlist;
begin
list := makelist;
DoStuff(list);
list.free; //ok
end;
procedure TForm1.Button_BAD_Click(Sender: TObject);
begin
listbox1.items.Assign(makelist); // <---- memory leak here because you forgot to free
end;
I put this note here before anyone will start 'picking' on my explanation. I used some 'shortcuts' in my explanation in order to avoid complex concepts (such as pointer assignment) keep things very simple. @gath asked a basic question which means that he is still learning the basics of programming.
Don't free the object before you are done invoking the methods on it. You are currently invoking the Count method on a destroyed object, hence the error.
Why don't you create the string list in the calling function instead, and pass its reference to the method that fills it? Or make the string list a member of a class, and free it when you free the class that owns it?
Either as Out variable.
function GetList(Parameter1: string; out ResultList: TStringList): boolean;
begin
// either
if not Assigned(ResultList) then
raise Exception.Create('Out variable is not declared.');
// or
Result := False;
if not Assigned(ResultList) then
Exit;
ResultList.Clear;
ResultList.Add('Line1');
ResultList.Add('Line2');
//...
Result := True;
end;
Or as string.
function GetList(Parameter1: string): string;
var
slList: TStringList;
begin
slList := TStringList.Create;
try
slList.Clear;
slList.Add('Line1');
slList.Add('Line2');
//...
Result := slList.Text;
finally
slList.Free;
end;
end;
.
procedure Main;
var
slList: TStringList;
begin
slList := TStringList.Create;
try
// either
GetList(Parameter1, slList);
// or
slList.Text := GetList(Parameter1);
// process slList...
finally
slList.Free;
end;
end;
Another possibility is to use a dynamic array instead of a TStringList. Since arrays are reference counted, you will never have to worry about freeing it.