简体   繁体   English

Delphi:为什么FreeAndNil *真的没有我的对象?

[英]Delphi: why doesn't FreeAndNil *really* nil my object?

I want to pass an object A to a second object B, have B do some processing and finally release A in case it's not needed anymore. 我想将对象A传递给第二个对象B,让B做一些处理,最后释放A以防不再需要它。 A watered down version is given below. 下面给出了一个淡化版本。

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.

(Never mind the awful design.) Now, what I don't understand is why FreeAndNil actually does free MyObject, yet Assigned(MyObject) is evaluated to true (giving an AV at MyObject.Free() ). (不要介意糟糕的设计。)现在,我不明白为什么FreeAndNil实际上释放MyObject,但Assigned(MyObject)被评估为true(在MyObject.Free()给出一个AV)。

Could someone please help enlighten me? 有人可以帮忙赐教吗?

MyObject is a different variable from the field FMyObject . MyObject是与FMyObject字段不同的变量。 And you're only nil ing the field FMyObject . 而你只nil荷兰国际集团现场FMyObject

FreeAndNil frees to object pointed to, and nil s the variable you passed in. It doesn't magically discover and nil all other variables that point to the object you freed. FreeAndNil释放到指向的对象,并且nil是你传入的变量。它不会神奇地发现并且nil指向你释放的对象的所有其他变量。

FreeAndNil(FMyObject); does the same thing as: 做同样的事情:

object(FMyObject).Free();
FMyObject=nil;

(Technically this is not entirely correct, the cast to object is a reinterpret cast due to the untyped var parameter, but that's not relevant here) (从技术上讲,这不完全正确,由于无类型的var参数,对象的强制转换是重新解释,但这与此无关)

And that obviously only modifies FMyObject and not MyObject 而这显然只会修改FMyObject而不是MyObject


Oh I just noticed that you're hiding the original Free method? 哦,我刚注意到你隐藏了原来的Free方法? That's insane. 那太疯狂了。 FreeAndNil still uses the original Free . FreeAndNil仍使用原版Free That doesn't hit you in your example because you call Free on a variable with the static type TBigObject and not FreeAndNil . 在你的例子中没有出现这种情况,因为你使用静态类型TBigObject而不是FreeAndNil对变量调用Free But it's a receipt for disaster. 但它是灾难的收据。

You should instead override the destructor Destroy . 你应该改写析构函数Destroy

The reason is simple, you nil one reference but not the other. 原因很简单,你只需要一个参考而不是另一个参考。 Consider this example: 考虑这个例子:

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;

You have two copies of the reference to the object but are only setting one of them to nil. 您有两个对象的引用副本,但只将其中一个设置为nil。 Your code is equivalent to this: 您的代码等同于:

i := 1;
j := i;
i := 0;
Writeln(j);//outputs 1

I'm using integers in this example because I'm sure you are familiar with how they work. 我在这个例子中使用整数,因为我确信你熟悉它们的工作方式。 Object references, which are really just pointers, behave in exactly the same way. 对象引用实际上只是指针,其行为方式完全相同。

Casting the example in terms of object references makes it look like this: 根据对象引用来铸造示例使它看起来像这样:

obj1 := TObject.Create;
obj2 := obj1;
obj1.Free;//these two lines are
obj1 := nil;//equivalent to FreeAndNil
//but obj2 still refers to the destroyed object

Aside: You should never call Destroy directly and never declare a method called Free. 旁白:你永远不应该直接调用Destroy,也不要声明一个名为Free的方法。 Instead override Destroy and call the static Free defined in TObject, or indeed FreeAndNil. 而是覆盖Destroy并调用TObject中定义的静态Free,或者实际上是FreeAndNil。

There are a few peculiarities in your code. 您的代码中有一些特殊之处。

First, you should not re-write Free, you should override the virtual destructor (Destroy) of your class. 首先,你不应该重写Free,你应该覆盖你的类的虚拟析构函数(Destroy)。

But ISTM that BigObject is not the owner of MyObject, so BigObject should not try to free it at all. 但ISTM认为BigObject不是MyObject的所有者,因此BigObject根本不应该尝试释放它。

As CodeInChaos already said, FreeAndNil only frees one variable, in this case the FMyObject field. 正如CodeInChaos已经说过的,FreeAndNil只释放一个变量,在本例中是FMyObject字段。 FreeAndNil is not required anyway, since nothing can happen after the object was freed. 无论如何都不需要FreeAndNil,因为在释放对象后不会发生任何事情。

Assigned can't be used to check if an object was freed already. Assigned不能用于检查对象是否已被释放。 It can only check for nil, and FreeAndNil only sets one reference to nil, not the object itself (this is impossible). 它只能检查nil,而FreeAndNil只设置一个对nil的引用 ,而不是对象本身(这是不可能的)。

Your program design should be thus, that an object can and will only be freed if nothing is accessing it anymore. 因此,您的程序设计应该是一个对象只有在没有任何东西可以访问它的情况下才能被释放。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM