为什么即使在调用后也分配了Delphi对象.Free?

时间:2008-10-24 19:50:10

标签: delphi

在Delphi中,为什么在调用析构函数后,Assigned()函数仍然返回True?

以下示例代码将“sl仍然分配给”控制台。

但是,我可以打电话给FreeAndNil(sl);它不会被分配。

我已经在Delphi中编程了一段时间,但这对我来说没有意义。

有人可以解释一下吗?

program Project1;
{$APPTYPE CONSOLE}
uses SysUtils, Classes;

var
  sl : TStringList;

begin
  sl := TStringList.Create;
  sl.Free;
  if Assigned(sl) then
    WriteLn('sl is still assigned')
  else
    WriteLn('sl is not assigned');
end.

我尝试比较VCL操作...... FreeAndNil简短而且很有意义:

procedure FreeAndNil(var Obj);
var
  P: TObject;
begin
  P := TObject(Obj);
  TObject(Obj) := nil;  // clear the reference before destroying the object
  P.Free;
end;

但TObject.Free是神秘的汇编程序,我不明白:

procedure TObject.Free;
asm
        TEST    EAX,EAX
        JE      @@exit
        MOV     ECX,[EAX]
        MOV     DL,1
        CALL    dword ptr [ECX].vmtDestroy
@@exit:
end;

4 个答案:

答案 0 :(得分:37)

如果使用sl.Free,则释放对象,但变量sl仍然指向现在无效的内存。

使用FreeAndNil(sl)释放对象并清除指针。

顺便说一下,如果你这样做:

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;

答案 1 :(得分:14)

Delphi VCL'对象'实际上总是指向对象的指针,但这方面通常对您隐藏。只需释放对象就会使指针悬空,所以你应该使用FreeAndNil。

“神秘的汇编程序”大致翻译为:

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

因为首先免费检查NIL,所以多次调用FreeAndNil是安全的......

答案 2 :(得分:3)

TObject的Free方法就像C ++中的“delete operator”。调用free将首先调用Destroy函数,然后释放为该对象分配的内存块。默认情况下,指向内存的指针不会设置为零,因为这会占用一条指令。

在大多数情况下,正确的做法是不要将指针设置为零,因为在大多数情况下它并不重要。但是,有时它很重要,所以你应该只为这些情况指针。

例如。在创建对象然后在函数末尾释放的函数中,没有必要将变量设置为零,因为这只是浪费cpu时间。

但对于稍后可能再次引用的全局对象或字段,应将其设置为零。使用FreeAndNil或者只是将指针设置为nil,无所谓。但请远离默认情况下不需要归零的归零变量。

答案 3 :(得分:1)

我们有简单的规则:

  1. 如果您想使用Assigned()检查是否已创建对象Obj, 然后确保使用FreeAndNil(Obj)释放它。

  2. Assigned()仅表示是否已分配地址。

  3. 本地对象引用总是被分配一个垃圾地址(一些随机地址),所以最好在使用它之前将其设置为nil。

  4. 示例:(这不是完整代码)

    {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;