delphi - Free() 方法实际上在内部做了什么以及它如何处理对象引用?

标签 delphi memory object-reference

问题

在下面的代码中,创建了一个 TStringList 类型的新对象,并将其传递给使用该对象的过程。通过将对象传递给方法 ProcToFillStringList,通过复制引用来创建新的对象引用。我对这段代码的疑问是:

  1. 存储在参数 SList 中的对象引用会发生什么情况 方法返回后?它是否删除了对该对象的引用 从堆栈中?

  2. Free() 方法内部实际上做了什么?它是从堆栈中删除对该对象的所有引用还是删除 物体本身?哪些引用被删除?

  3. 当方法返回时,对象引用(而不是对象本身)是否会自动从堆栈中删除?

  4. 通过引用传递引用会更好吗?

代码

var
  SL: TStringList; // first object reference
begin
  SL := TStringList.Create; // creating object
  try
    ProcToFillStringList(SL);
  finally
    SL.Free; // -> what gets 'freed' here? the object? the references? both?
  end;
end;

procedure ProcToFillStringList(const SList: TStrings); // second object reference
  SList.Add('x'); // not calling Free -> does the reference get removed?
end;

最佳答案

以下是较新版本的 Delphi 上的 Free 方法的代码:

procedure TObject.Free;
begin
// under ARC, this method isn't actually called since the compiler translates
// the call to be a mere nil assignment to the instance variable, which then calls _InstClear
{$IFNDEF AUTOREFCOUNT}
  if Self <> nil then
    Destroy;
{$ENDIF}
end;

有两种不同的情况。当编译到具有自动引用计数的环境(即 iOS)时,Free 根本不起作用,仅当删除对它们的最后一个引用时才释放对象(但正如上面代码的注释中所述,编译器会更改您的 SL.FreeSL:=nil,因此如果它是对对象的最后一个引用,它将被释放并且 SL 真正设置为 nil。

但在所有其他平台中,对象不进行引用计数。当调用 Free 时,对象内存被释放,但你的变量不会自动设置为 nil (不是说另一个变量指向同一个对象),使用这样的语法是不可能的。对象的任何方法都不能更改调用它的变量。这就是为什么您要编写 SL := TStringList.Create 而不是 SL.Create。在第一种情况下,您将获得创建对象的新内存地址并将 SL 分配给它。在第二个 SL 中,未初始化并且可以指向任何地方,因此无法准确地在那里创建对象。

那么,回答你的问题:

  1. 本地过程中的对象引用超出范围时将被删除。但是,如果您使用 const 或 var 参数,则首先不会创建它。实际上,您在这里使用相同的引用 SL。

  2. 在 iOS 中,Free 不执行任何操作,当 SL 变量超出范围时,对象将自动销毁。在其他平台中,Free 会销毁对象并且根本不影响其他引用。

  3. 是的,他们确实如此。

  4. 使用最能描述您情况的修饰语。 Const 将告诉编译器和使用您的代码的人员(包括您自己),参数在过程中不会更改,编译器可以按值(对于小于指针的对象)或按引用传递它,但不能无论它选择什么,引用计数都不会增加,因此从这个角度来看,您可以认为您使用了完全相同的对象,就像它是通过引用传递的一样。

使用 Var (通过引用)您可能会意外更改传递给过程的变量,这会使您的意图不清楚,因此仅当您确实想要更改此变量和 Const 时才使用它 否则。

关于delphi - Free() 方法实际上在内部做了什么以及它如何处理对象引用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37226384/

相关文章:

c# - 我怎样才能引用一个已经声明的对象

java - 重新分配对象引用时出现意外输出

javascript - array.forEach 的 thisArg 没有按预期引用

delphi - 如何声明仅存在于 Windows 8 上的外部函数而不会使应用程序在 Windows 7 及更低版本上崩溃?

vb.net - Delphi到VBNet代码转换(如何?)

Java 相等运算符

c - 多个结构的预分配 - 相同的结构

c++ - 将字符串添加到 vector<string> 循环时内存损坏

delphi - 在RAD Studio中检查更新的问题

delphi - 如何在 Delphi 可执行文件中嵌入二进制文件并在运行时提取?