How to safely Create and Free multiple objects in Delphi

前端 未结 2 1504
灰色年华
灰色年华 2021-01-11 13:41

How should you safely create and free multiple objects?

Basically, this sort of thing:

  newOrderSource := TWebNewOrderSource.Create();
  twData := T         


        
2条回答
  •  隐瞒了意图╮
    2021-01-11 13:58

    As I'm sure everyone knows, the standard way to manage an object is like this:

    A := TMyObject.Create;
    try
      A.DoSomething;
    finally
      A.Free;
    end;
    

    If there is an exception in TMyObject.Create then the destructor will be called and then the exception raised. In that case A will not be assigned to.

    When you have multiple objects you can repeat the pattern:

    A := TMyObject.Create;
    try
      B := TMyObject.Create;
      try
        A.DoSomething;
        B.DoSomething;
      finally
        B.Free;
      end;
    finally
      A.Free;
    end;
    

    This very quickly becomes a mess and hence the question.

    A standard trick is to take advantage of the fact that Free can safely be called on a nil object reference.

    A := nil;
    B := nil;
    try
      A := TMyObject.Create;
      B := TMyObject.Create;
      A.DoSomething;
      B.DoSomething;
    finally
      B.Free;
      A.Free;
    end;
    

    This does have the minor weakness that it is not resilient to exceptions being raised in B.Free but it is not unreasonable to regard this as a failure condition that can be ignored. Destructors should not raise exceptions. If they do then your system is probably broken irredeemably.

    This pattern above can become a little messy as more objects are added so I personally use the following helper methods.

    procedure InitialiseNil(var Obj1); overload;
    procedure InitialiseNil(var Obj1, Obj2); overload;
    procedure InitialiseNil(var Obj1, Obj2, Obj3); overload;
    
    procedure FreeAndNil(var Obj1); overload;
    procedure FreeAndNil(var Obj1, Obj2); overload;
    procedure FreeAndNil(var Obj1, Obj2, Obj3); overload;
    

    In fact my code has versions with even more parameters. For ease of maintenance this code is all automatically generated from a short Python script.

    These methods are implemented in the obvious way, e.g.

    procedure FreeAndNil(var Obj1, Obj2);
    var
      Temp1, Temp2: TObject;
    begin
      Temp1 := TObject(Obj1);
      Temp2 := TObject(Obj2);
      Pointer(Obj1) := nil;
      Pointer(Obj2) := nil;
      Temp1.Free;
      Temp2.Free;
    end;
    

    This allows us to re-write the sample above like this:

    InitialiseNil(A, B);
    try
      A := TMyObject.Create;
      B := TMyObject.Create;
      A.DoSomething;
      B.DoSomething;
    finally
      FreeAndNil(B, A);
    end;
    

提交回复
热议问题