con*_*tor 5 delphi memory-management
我想将对象A传递给第二个对象B,让B做一些处理,最后释放A以防不再需要它.下面给出了一个淡化版本.
program Project6;
{$APPTYPE CONSOLE}
uses
SysUtils;
type
TMyObject = class(TObject)
public
FField1: string;
FField2: string;
end;
TBigObject = class(TObject)
public
FMyObject: TMyObject;
procedure Bind(var MyObject: TMyObject);
procedure Free();
end;
procedure TBigObject.Bind(var MyObject: TMyObject);
begin
FMyObject := MyObject;
end;
procedure TBigObject.Free;
begin
FreeAndNil(FMyObject);
Destroy();
end;
var
MyObject: TMyObject;
BigObject: TBigObject;
begin
try
MyObject := TMyObject.Create();
BigObject := TBigObject.Create();
BigObject.Bind(MyObject);
BigObject.Free();
if (Assigned(MyObject)) then begin
WriteLn('Set MyObject free!');
MyObject.Free();
end;
ReadLn;
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
end.
Run Code Online (Sandbox Code Playgroud)
(不要介意可怕的设计.)现在,我不明白为什么FreeAndNil实际上释放MyObject,但Assigned(MyObject)被评估为真(给AV一个MyObject.Free()).
有人可以帮忙赐教吗?
Cod*_*aos 15
MyObject是与该领域不同的变量FMyObject.而你只是nil在这个领域FMyObject.
FreeAndNil释放到指向的对象,以及nil传入的变量.它不会神奇地发现,并且nil所有其他变量都指向您释放的对象.
FreeAndNil(FMyObject); 做同样的事情:
object(FMyObject).Free();
FMyObject=nil;
Run Code Online (Sandbox Code Playgroud)
(从技术上讲,这不完全正确,由于无类型var参数,对对象的强制转换是重新解释,但这与此无关)
而这显然只是修改FMyObject而不是MyObject
哦,我刚注意到你隐藏了原来的Free方法?那太疯狂了.FreeAndNil仍然使用原件Free.在你的例子中,这并没有打你,因为你调用的Free是静态类型的变量TBigObject而不是FreeAndNil.但它是灾难的收据.
您应该改写析构函数Destroy.
Ond*_*lle 14
原因很简单,你只需要一个参考而不是另一个参考.考虑这个例子:
var
Obj1, Obj2: TObject;
begin
Obj1 := TObject.Create;
Obj2 := Obj1;
FreeAndNil(Obj1);
// Obj1 is released and nil, Obj2 is non-nil but now points to undefined memory
// ie. accessing it will cause access violations
end;
Run Code Online (Sandbox Code Playgroud)
您有两个对象的引用副本,但只将其中一个设置为nil.您的代码等同于:
i := 1;
j := i;
i := 0;
Writeln(j);//outputs 1
Run Code Online (Sandbox Code Playgroud)
我在这个例子中使用整数,因为我确信你熟悉它们的工作方式.对象引用实际上只是指针,其行为方式完全相同.
根据对象引用来铸造示例使它看起来像这样:
obj1 := TObject.Create;
obj2 := obj1;
obj1.Free;//these two lines are
obj1 := nil;//equivalent to FreeAndNil
//but obj2 still refers to the destroyed object
Run Code Online (Sandbox Code Playgroud)
旁白:你永远不应该直接调用Destroy,也不要声明一个名为Free的方法.而是覆盖Destroy并调用TObject中定义的静态Free,或者实际上是FreeAndNil.