0

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.

6
  • Does SomeForm.MyContainer.Controls[0] return a pointer or a copy? If it returns a copy then you are free and nilling the copy -> C will be nil. If it is a pointer then the SomeForm.MyContainer.Controls[0] should be nil So try to figure out what gets returned.... Commented Aug 12, 2015 at 12:21
  • @Blaatz0r Controls[] is an indexed property of TWinControl that returns a TControl, which is, of course, a reference. Commented Aug 12, 2015 at 12:23
  • @DavidHeffernan didn't notice the SomeForm before the .MyContainer :) Commented Aug 12, 2015 at 12:24
  • @DavidHeffernan, The control reference is found in TSomeForm (FActiveControl) - but suppose I can't access this reference directly. Mybe the question should have been "How to free and nil an unknown object reference by reference/pointer"? Commented Aug 12, 2015 at 12:41
  • @Zig You know how to free the control. If you don't explicitly keep a reference to the control when you create it, there is nothing to nil. That would be the final paragraph of my answer. Commented Aug 12, 2015 at 12:43

2 Answers 2

2

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.

Sign up to request clarification or add additional context in comments.

5 Comments

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.
And I meant FActiveControl or FMyActiveControl (not the ActiveControl property) which has the reference to that instance.
OK. As it happens, the property is a straight read of the field: property ActiveControl: TWinControl read FActiveControl
My question referred to a situation where I cant access FActiveControl or property ActiveControl. and had only a local reference as C := SomeForm.MyContainer.Controls[0]
The basic rule is that if you have a reference that outlives the object then you should consider clearing that reference. In your scenario you don't have a reference that outlives the object.
2

An object instance cannot be nilled, and in this case there is no need for any reference to set to nil.

If Container.Controls[0] is valid, then Container is the control's parent. When you free that control, the VCL takes care of extracting a gone child from a parent, so after you free Container.Controls[0], ControlCount will be 0 and Container.Controls[0] will be invalid.

1 Comment

plus one for "An object instance cannot be nilled".

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.