Why are Delphi objects assigned even after calling .Free?

后端 未结 4 1043
遥遥无期
遥遥无期 2020-11-30 04:58

In Delphi, why does the Assigned() function still return True after I call the destructor?

The below example code will write \"sl is still assigned\" to the console.

相关标签:
4条回答
  • 2020-11-30 05:16

    We have simple rules:

    1. If you want to use Assigned() to check if an object Obj is already created or not, then make sure you use FreeAndNil(Obj) to free it.

    2. Assigned() only says if an address is assigned or not.

    3. The local object reference is always assigned a garbage address (some random address), so it is good to set it to nil before using it.

    Example: (This is not the full code)

    {Opened a new VCL application, placed a Button1, Memo1 on the form
    Next added a public reference GlobalButton of type TButton
    Next in OnClick handler of Button1 added a variable LocalButton 
    Next in body, check if GlobalButton and LocalButton are assigned}
    
      TForm2 = class(TForm)
        Button1: TButton;
        Memo1: TMemo;
        procedure Button1Click(Sender: TObject);
      private
        { Private declarations }
      public
        { Public declarations }
        GlobalButton: TButton;
      end;
    
    procedure TForm2.Button1Click(Sender: TObject);
    var
      LocalButton: TButton;
    begin
      if Assigned(GlobalButton) then  
        Memo1.Lines.Add('GlobalButton assigned');
      if Assigned(LocalButton) then  
        Memo1.Lines.Add('LocalButton assigned');
    end;
    
    0 讨论(0)
  • 2020-11-30 05:17

    The Free method of TObject is like the "delete operator" in C++. Calling free will first call the Destroy function and then it will free the memory block that was allocated for the object. By default the pointer to the memory is not then set to zero because this will use up one instruction.

    The correct thing to do in most cases is not to set the pointer to zero because in most cases it does not matter. However, sometimes it is important and so you should only nil the pointer for those cases.

    For example. In a function where an object is created and then freed at the end of the function there is no point in setting the variable to zero since that is just wasting cpu time.

    But for a global object or field that might be referenced again later you should set it to zero. Use FreeAndNil or just set the pointer to nil yourself, does not matter. But stay away from zeroing variables that do not need to be zeroed by default.

    0 讨论(0)
  • 2020-11-30 05:19

    If you use sl.Free, the object is freed but the variable sl still points to the now invalid memory.

    Use FreeAndNil(sl) to both free the object and clear the pointer.

    By the way, if you do:

    var
      sl1, sl2: TStringList;
    begin
      sl1 := TStringList.Create;
      sl2 := sl1;
      FreeAndNil(sl1);
      // sl2 is still assigned and must be cleared separately (not with FreeAndNil because it points to the already freed object.)
    end;
    
    
    
    
    procedure TObject.Free;
    asm
        TEST    EAX,EAX
        JE      @@exit              // Jump to exit if pointer is nil.
        MOV     ECX,[EAX]           
        MOV     DL,1
        CALL    dword ptr [ECX].vmtDestroy  // Call cleanup code (and destructor).
    @@exit:
    end;
    
    0 讨论(0)
  • 2020-11-30 05:39

    Delphi VCL 'objects' are actually always pointers to objects, but this aspect is typically hidden from you. Just freeing the object leaves the pointer dangling around, so you should use FreeAndNil instead.

    The "Mysterious Assembler" translates roughly to:

    if Obj != NIL then
      vmtDestroy(obj);  // which is basically the destructor/deallocator.
    

    Because Free checks for NIL first, it's safe to call FreeAndNil multiple times...

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