Delphi Return Function Class Object

In addition to this question, I did some tests and research on docwiki. I came to the conclusion that such code should work without memory leaks:

function testResultObject: TClassA;
begin
 Result := TClassA.Create;
 Result.DoSomething;
end;

And then I can call the above code as follows:

var k: TClassA;
begin

 k := testResultObject;
 try
  //code code code
 finally
  k.Free;
 end;

end;

As Remy said in the answer, it is better to avoid doing things and instead use something like that testResultObject(x: TClassA): boolean. In this case, return true / false can tell me if everything is in order, and I pass the already created object.

Take a look at this code:

function testResultObject: TClassA;
begin

 Result := TClassA.Create;

 try
  Result.DoSomething;
 except
  Result.Free;
 end;

end;

The problem with the first version of the above function is what DoSomethingmight throw an exception, and if that happens, I will skip memory. Could a second implementation with try-exceptbe a solution? Of course, later I will need to check whether the result is assigned or not.

, ( ) testResultObject(x: TClassA): boolean . , return-a-class, .

+4
3

. .

. :

function testResultObject: TClassA;
begin
  Result := TClassA.Create;    
  try
    Result.DoSomething;
  except
    Result.Free;
    raise;
  end;
end;

, . , .

, , . :

obj := testResultObject;
try
  // do things with obj
finally
  obj.Free;
end;
+9

, .

  • ( J), , - .
  • , , . ; .

:

         {Name has a clue that caller should take ownership of a new object returned}
function CreateObjectA: TClassA;
begin
  {Once object is successfully created, internal resource protection is required:
      - if no error, it is callers responsibility to destroy the returned object
      - if error, caller must assume creation *failed* so must destroy object here
  Also, by assigning Result of successful Create before *try*:
      The object (reference) is returned
          **if-and-only-if**
      This function returns 'normally' (i.e. no exception state)}
  Result := TClassA.Create;    
  try
    Result.DoSomething; {that could fail}
  except
    {Cleanup only if something goes wrong:
      caller should not be responsible for errors *within* this method}
    Result.Free;
    {Re-raise the exception to notify caller:
      exception state means caller does not "receive" Result...
      code jumps to next finally or except block}
    raise;
  end;
end;

, : / , TObject.Create.
, .

, J FreeAndNil, , : , , AV. , , :

var k: TClassA;
begin
  k := testResultObject; {assuming nil result on failed create, next/similar is *required*}
  if Assigned(k) then    {Note how this differs from normal try finally pattern}
  try
    //code using k
  finally
    k.Free;
  end;
end;

. , ; .


, , testResultObject , , . , ? , , .

var k: TClassA;
begin
  k := TClassA.Create;
  try
    testResultObject(k); {Where this is simply implemented as k.DoSomething;}
    //more code using k
  finally
    k.Free;
  end;
end;
+5

:

 function testResultObject: TClassA;
 begin
   Result := TClassA.Create;    
   try
     Result.DoSomething;
   except
     Result.Free;
   end;
 end;

, . ; - (), . nil, , , . ( nil), :

try
  Result.DoSomething;
except
  FreeAndNil(Result);
end;

, nil ( Assigned ) . , , . .

TFoo = class
  public
    constructor Create(ADoSomething : boolean = false);
    procedure DoSomething;
end;

constructor TClassA.Create(ADoSomething: Boolean = False);
begin
  inherited Create;
  if ADoSomething then DoSomething;
end;

procedure TClassA.DoSomething;
begin
  //
end;

This way you can get rid of all exception handling and just call it like:

function testResultObject: TClassA;
begin
  Result := TClassA.Create(true);     
end;

Since you now clicked on execution DoSomethingin the constructor, any exceptions would naturally trigger the destructor, and memory management issues would disappear. Other answers also have good solutions.

+4
source

Source: https://habr.com/ru/post/1684463/


All Articles