如何通过 reference/pointer 释放和 nil 一个未知的对象实例?

How to free and nil an unknown object instance by reference/pointer?

我有一个包含单个控件的容器。此控件可以是少数类型之一(TMyFrame 后代)。正在 运行 时间创建和销毁控件。

在某些时候我需要释放 nil 这个控件:

var
  C: TControl;

  C := SomeForm.MyContainer.Controls[0];
  C.Free;
  C := nil;

但问题是控件实例本身没有设置为nil

这可能吗?


我想关键是一个实例可以有很多对它的引用。我刚刚意识到一个参考不能 "see" 所有其他未知参考。

对象实例不能为空,在这种情况下不需要任何引用设置为 nil

如果 Container.Controls[0] 有效,则 Container 是控件的父级。当您释放该控件时,VCL 会负责从父项中提取已消失的子项,因此在您释放 Container.Controls[0] 后,ControlCount 将变为 0,而 Container.Controls[0] 将无效.

更新

根据您的评论,您在动态创建控件时并未存储对控件的引用。在这种情况下,您无需将任何内容设置为 nil.

VCL 框架本身包含对控件的各种引用。但是这些是由框架管理的。你提到 ActiveControl。如果您销毁活动控件,则框架会负责管理 ActiveControl 属性。

除了销毁控件之外,您不需要做任何事情。 不需要清除引用,因为没有引用。


有一种机制可以自动设置对 nil 的引用。它在 TComponent 中实现。在 TComponent 的析构函数中有一个对 SetReference(False) 的调用,它是这样实现的:

procedure TComponent.SetReference(Enable: Boolean);
var
  Field: ^TComponent;
begin
  if (FOwner <> nil) then
  begin
    Field := FOwner.FieldAddress(FName);
    if Field <> nil then
      if Enable then Field^ := Self else Field^ := nil;
  end;
end;

所以,假设您有这样的表单:

type
  TForm1 = class(TForm)
    Button1: TButton;
    Button2: TButton;
    procedure Button2Click(Sender: TObject);
  end;

其中两个按钮是由表单流框架创建的。假设在 Button2Click 中你写 Button1.Free。然后调用 SetReference 会将 Button1 变量设置为 nil.

现在,您正在谈论在运行时创建的控件。您没有向我们展示如何定义未设置为 nil 的引用。如果你想安排引用自动设置为 nil 你需要执行以下操作:

  1. 将引用声明为控件 Owner 的已发布字段。
  2. 确保控件的 Name 与您在步骤 1 中声明的已发布字段相同。

如果不能这样做,则需要手动编写代码以将引用设置为 nil。这样做:

SomeReference := nil;

现在,我不知道你将如何获得SomeReference。只有你自己知道。因为只有您知道要设置为 nil 的此引用的位置。

或者整个问题可能完全是个误会。也许您没有对动态创建的控件的引用。在这种情况下,使用 Controls[] 或其他一些方法来定位控件,调用 Free,工作就完成了。