How do i return an object from a function in Delphi without causing Access Violation?

后端 未结 10 1235
被撕碎了的回忆
被撕碎了的回忆 2021-02-13 14:54

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         


        
相关标签:
10条回答
  • 2021-02-13 15:17

    You simply cannot free something and then expect to reference it later. That is the wrong way. You have two basic options:

    • Do not call free, and make the caller responsible for disposing of the object
    • Have the caller pass in an object so that it's responsible for both Create and Free

    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.

    0 讨论(0)
  • 2021-02-13 15:19

    both are reffering to same memory,if you free it both will get freed.......

    0 讨论(0)
  • 2021-02-13 15:21

    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.

    0 讨论(0)
  • 2021-02-13 15:22

    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?

    0 讨论(0)
  • 2021-02-13 15:24

    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;
    
    0 讨论(0)
  • 2021-02-13 15:25

    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.

    0 讨论(0)
提交回复
热议问题