在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;
答案 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)
我们有简单的规则:
如果您想使用Assigned()
检查是否已创建对象Obj
,
然后确保使用FreeAndNil(Obj)
释放它。
Assigned()
仅表示是否已分配地址。
本地对象引用总是被分配一个垃圾地址(一些随机地址),所以最好在使用它之前将其设置为nil。
示例:(这不是完整代码)
{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;