Search code examples
delphidelphi-7

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


I have a container which hold a single control. this control can be one of few types (TMyFrame descendants). the controls are being created and destroyed at run time.

At some point I need to Free and nil this control:

var
  C: TControl;

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

But the problem is that the control instance itself is not set to nil.

Is this possible?


I guess the key point is that an instance could have many references to it. I just realized that one reference cannot "see" all other unknown references.


Solution

  • Update

    According to your comment, you are not storing a reference to the control when you create it dynamically. In which case there is no need for you to set anything to nil.

    The VCL framework itself holds various references to controls. But these are managed by the framework. You mention ActiveControl. If you destroy the active control then the framework takes care of managing the ActiveControl property.

    There is simply nothing you need to do beyond destroying the control. You don't need to clear a reference because you did not take a reference.


    There is a mechanism for automatically setting references to nil. It is implemented in TComponent. In the destructor of TComponent there is a call to SetReference(False) is made and that is implemented like this:

    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;
    

    So, suppose that you have a form like this:

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

    where the two buttons are created by the form streaming framework. Suppose that in Button2Click you write Button1.Free. Then the call to SetReference will set the Button1 variable to nil.

    Now, you are talking about a control created at runtime. You did not show us how you defined the reference that is not being set to nil. If you want to arrange that the reference is automatically set to nil you need to do the following:

    1. Declare the reference as a published field of the control's Owner.
    2. Ensure that the control's Name is the same as the published field you declared in step 1.

    If you cannot do that, then you will need to manually write code to set the reference to nil. Do that like this:

    SomeReference := nil;
    

    Now, I don't know how you are going to get hold of SomeReference. Only you can know that. Because only you know the location of this reference that you wish to set to nil.

    Or perhaps the whole question is a complete misunderstanding. Perhaps you do not have a reference to the dynamically created control. In which case, use Controls[] or some other means to locate the control, call Free, and the job is done.