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

后端 未结 10 1259
被撕碎了的回忆
被撕碎了的回忆 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:27

    As Smasher said, you can't free it; the code calling the function that returns the object is responsible for destroying it.

    This is bad code design, by the way, as it makes it confusing as to who allocates and frees. A much better way to do it would be to have the caller create the object and pass it in to the function. That way, the code that creates it also frees it. Something like this:

    var
      SL: TStringList;
    begin
      SL := TStringList.Create;
      try
        ProcToFillStringList(SL);
        //Do something with populated list
      finally
        SL.Free;
      end;
    end;
    
    // Note I've made the parameter a TStrings and not a TStringList. This allows
    // passing a TMemo.Lines or a TListBox or TComboBox Items as well.
    procedure ProcToFillStringList(const SList: TStrings);
      // Do whatever populates the list with SList.Add()
    end;
    

    Now there's no confusion over who does what - the same code that creates the object is responsible for freeing it. And the code, IMO, is much clearer to read and maintain.

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

    How can i return the TStringList and still free it in the local function?

    You can't. If you free it in the local function, you can't use the return value. Result and vStrList point to the same TStringList object in memory. TStringList is a class and

    Result := vStrList
    

    does therefore not copy the string list, but only copies the reference.

    So, instead you should free the string list in the calling context after you're done working with it or pass the string list as a parameter to your function like this

    procedure FuncStringList (StringList : TStringList);
    

    and let the calling code create and free the string list. As pointed out by the other answers, this is the preferable way, since it makes ownership very clear.

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

    Simple answer: you can't. Why are you trying to? Is it because you've learned that you need to free every object you create in the same function in which they're created? That's generally correct, but not always, and this is one of the exceptions to the rule. A better way to put it is that every object must be freed by its owner.

    If you have a function that generates an object, like this one, but then passes it on to another function, it doesn't take ownership of the object. Remove the call to free and document it, so you (and anyone else who uses this function) will realize that it creates a new object that the code that calls it has to take ownership of.

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

    A policy I have with such situations is to pass the stringlist content through the text property and just pass the string returned to the function. This way there's no need to discuss who release who. Of course, you have to do a little more coding, but it's safer. The example is an adaptation of the Ken White's one :

    var
      SL: TStringList;
      Aux: String;
    begin
      SL := TStringList.Create;
      try
        SL.Text := ProcToFillStringList;
        //Do something with populated list
      finally
        SL.Free;
      end;
    end;
    
     // It receives a default param, in the case you have to deal with 
     // StringList with some previous content    
     function ProcToFillStringList(SListContent: String = ''):String;
     // Do the stuff you need to do with the content
    end;
    

    An exception is when all you have is the object and there's no way to retrieve the content on it through a safe type (in this case, strings); then I follow Ken White's idea.

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