When you call a function, do you need to release what you created in it or functions are done by everyone?

For example:

TPlayer = class type TSomeType = class class function myFunc(str: string): TPlayer; end; class function TSomeType.myFunc(str: string): TPlayer; var Player: TPlayer; begin Player.Param1 := 'qwer'; Player.Param2 := 3; Player.Param3.SubParam1 := TStringList.Create; Player.Param3.SubParam1.DelimitedText := 'qwe,asd,zxc'; Player.Param3.SubParam2 := False; Player.Param4. := TStringList.Create; Player.Param4.DelimitedText := 'rty,fgh,vbn'; Result := Player; end; Player := TSomeType.myFunc(str); 

Is it possible and necessary, after Result := Player; set Player := nil; ?

Or it is necessary to free each StringList separately? Or both?

If from the function, call another one and assign the result to a variable, should this variable also be released?

UPD

 unit myTypes; interface uses System.SysUtils, System.Classes, ExtCtrls, IdContext, Generics.Collections, Generics.Defaults, SyncObjs, IdHashMessageDigest; ... type TPlayer = class Name: String; Pass: String; Active: Boolean; Authorized: Boolean; Balance: Integer; Game: TPlayerGame; Oper: TPlayerParent; Admin: TPlayerParent; SuperAdmin: TPlayerParent; Session: String; TCPAddress: TIdContext; WSAddress: String; HttpAddress: String; HostWS: String; HostTcp: String; HostHttp: String; constructor Create(pName: String); destructor Destroy; override; end; implementation ... { TPlayer } constructor TPlayer.Create(pName: String); begin //Inherited; self.Name := pName; self.Pass := ''; self.Active := False; self.Authorized := False; self.Balance := 0; self.Game := TPlayerGame.Create; self.Oper := TPlayerParent.Create; self.Admin := TPlayerParent.Create; self.SuperAdmin := TPlayerParent.Create; Self.Session := ''; self.TCPAddress := nil; self.WSAddress := ''; self.HttpAddress := ''; self.HostWS := ''; self.HostTcp := ''; self.HostHttp := ''; end; destructor TPlayer.Destroy; begin self.Game.Destroy; self.Oper.Destroy; self.Admin.Destroy; self.SuperAdmin.Destroy; self.TCPAddress := nil; Inherited; end; end. 

Here are the scenarios (I tried to describe briefly so do not look for logic in the actions):

 function Authorizetion(login, pass): Boolean; var Player: TPlayer; begin // если авторизация удачна if Authorized then begin // создаю объект Player := TPlayer.Create(login); // добавляю объект в список TmyServer.SetPlayer(Player.Name, Player); // TDictionary.AddOrSetValue // я создал Player , потом добавил в TDictionary его копию, // а тот что в этой функцие, уничтожаю Player.Destroy; end; end; function LoadFromDateBase(name: String): TPlayer; var Player: TPlayer; begin // беру Player из TDictionary Player := TmyServer.GetPlayer(pName); // меняю некоторые значения на прочтенные из базы Player := FDQuaery.FieldByName().AsString; Result := Player; // тут я сохранил Player в Result(тот объект который вызвал эту функцию), // а теперь его уничтожаю Player.Destroy; end; 

    2 answers 2

    When you call a function, do you need to release what you created in it or functions are done by everyone?

    Correctly clearly separated who is responsible for creating and deleting objects.

    In theory, if your function creates an object and gives it to the caller, then now it is the responsibility of the caller to free the object.

    In the example with your class function, it is not clear what happens - you are not creating an object, but working with it. Initialization of nested objects also should not be at this level.

    Below is your code and notes / errors:

     class function TSomeType.myFunc(str: string): TPlayer; var Player: TPlayer; begin // не создается объект Player! Player.Param1 := 'qwer'; Player.Param2 := 3; // Объекты должны создаваться в конструкторах их владельцев // (SubParam1 должен создаваться внутри Player.Param3) Player.Param3.SubParam1 := TStringList.Create; Player.Param3.SubParam1.DelimitedText := 'qwe,asd,zxc'; Player.Param3.SubParam2 := False; Player.Param4. := TStringList.Create; // Опечатка, лишняя точка Player.Param4.DelimitedText := 'rty,fgh,vbn'; Result := Player; end; 

    Is it possible and necessary, after Result: = Player; put Player: = nil ;?

    It is possible, but meaningless and unnecessary. The variable is only a pointer to the object. Assigning nil (or any other value) does not affect anything. The exception is interfaces (ISomething) and objects on new platforms with ARC. They have reference counters, but you probably don't need to use it yet.

    Or it is necessary to free each StringList separately? Or both?

    Each created object must be released - yes. Sometimes objects are registered in some structures, then when exiting, the structure itself will release all objects stored in it (for example, Forms and their controls are made like this).

    If from the function, call another one and assign the result to a variable, should this variable also be released?

    You have porridge:

    • Variables do not need to be released. It is necessary to release the created objects.
    • It makes no sense to create an object and release it in a function that should return it.

    @Kromster I also try so hard to do, here’s a question, created an object, worked with it, put it in the result, destroyed the object, will nothing disappear in Result? due to the fact that destroyed the object, naturally after the assignment

    Once again, the variable is only the address of the object. Addresses can be changed, assigned, copied, deleted. Nothing happens to the object itself. Imagine that the object is you. And the variable with the address is a record about you in the phone book. You can book xerit, burn, reissue, cut and paste numbers. Nothing will happen to you from this. But .. if you delete, for example, then the entry in the book will become invalid, as in all its copies.
    Total - if you destroy the object, then all its "addresses" will become invalid. You will receive either an error or garbage data ("someone calls you, but you are no longer there, and who the hell answers for you")

    By the way, the example is not active, in practice everything is more intelligent, there is just a lot of code

    Doubt. You have no basic concepts about the life of objects. Read articles and a book on this topic!

    Here are the scenarios

    The error is that you call Player.Destroy; . You put in lists copies of pointers to the object. When you destroy an object, it turns out that in the list you have pointers to the freed memory , there will be object data until it overwrites them with another memory allocation and you get garbage.

    • Moreover, the Player variable is not needed here, you can work directly with Result: from the point of view of the function, it is the same variable as the Player. - Alekcvp
    • @Alekcvp I hold the position of one point of return in such cases - that is, we created an object, worked with it, and then put it into the result. - Kromster
    • @Kromster I also try so hard to do, here’s a question, created an object, worked with it, put it in the result, destroyed the object, will nothing disappear in Result? due to the fact that he destroyed the object, naturally after assignment - ArtGrek13
    • By the way, the example is not active, in practice everything is more literate, there is just a lot of code there - ArtGrek13
    • @Kromster added a question - ArtGrek13
     function LoadFromDateBase(name: String): TPlayer; var Player: TPlayer; begin // беру Player из TDictionary Player := TmyServer.GetPlayer(pName); // меняю некоторые значения на прочтенные из базы Player := FDQuaery.FieldByName().AsString; Result := Player; // тут я сохранил Player в Result(тот объект который вызвал эту функцию), // а теперь его уничтожаю Player.Destroy; // - ни в коем случае!!! end; // тут я сохранил Player в Result(тот объект который вызвал эту функцию), 

    No, you assigned a variable Result value, which is a link (to hell with it, let's say honestly - "pointer") to an object of type TPlayer , to which the variable Player has already pointed.

    You return a reference to an object of type TPlayer , and immediately release the memory that this object occupies. At any time, this memory can be used for something else that will overwrite the remains of your poor TPlayer .

    The same in Authorizetion .

      TPlayer = class private fName: String; fGame: TPlayerGame; fOper: TPlayerParent; fAdmin: TPlayerParent; fSuperAdmin: TPlayerParent; fTCPAddress: TIdContext; public Pass: String; Active: Boolean; Authorized: Boolean; Balance: Integer; Session: String; WSAddress: String; HttpAddress: String; HostWS: String; HostTcp: String; HostHttp: String; constructor Create(pName: String); destructor Destroy; override; property Name: String read fName; property Game: TPlayerGame read fGame; property Oper: TPlayerParent read fOper; property Admin: TPlayerParent read fAdmin; property SuperAdmin: TPlayerParent read fSuperAdmin; property TCPAddress: TIdContext read fTCPAddress write fTCPAddress; end; constructor TPlayer.Create(pName: String); begin Inherited Create; fName := pName; fGame := TPlayerGame.Create; fOper := TPlayerParent.Create; fAdmin := TPlayerParent.Create; fSuperAdmin := TPlayerParent.Create; end; destructor TPlayer.Destroy; begin FreeAndNil(fGame); FreeAndNil(fOper); FreeAndNil(fAdmin); FreeAndNil(fSuperAdmin); fTCPAddress := nil; Inherited; end; 

    In Delphi, the class fields when creating objects are initialized with values ​​corresponding to zeroed memory.

    Properties that do not have the write specifier are read-only and cannot be left of the assignment operator.

    The value of the player's name is assigned in the constructor and, it seems, does not change during the lifetime of the object. Bringing it out as a read-only property allows you to catch the erroneous assignment of a new value to it by the outer code at the compilation stage.

    • Comments are not intended for extended discussion; conversation moved to chat . - Nick Volynkin