5

Currently, I am trying to understand Delphi's VCL, specifically, the notification mechanism (which is a great mechanism in my point of view).

When I was studying on this subject, I remembered of the TLabeledEdit, of course I have been using it for long time, but I never had chance to stop and study it's code.

As I understand so far:

When a TComponent is destroyed:

  1. It will notify all its children's components, to include csDestroying in its state.
  2. FreeNotifiers part. I can't understand.
  3. Will iterate the components list and:
    1. Remove each item from the components list
    2. Actually destroy each component instance.

When a child component is being destroyed, it restarts the same process for all of its children components. So, as far as I can tell, this is a chain effect.

What I can't understand is the FreeNotification, what could I possibly do with it?

Let's think about the TLabeledEdit in first place. The relevant part of the notification, in TLabeledEdit's code is an override on the Notification function, with the following code:

  if (AComponent = FEditLabel) and (Operation = opRemove) then
    FEditLabel := nil;

What could have happened if FreeNotification was not used?

In General, what benefits would I have because of this mechanism and what am I not seeing that might eventually make its existence necessary?

EProgrammerNotFound
  • 2,403
  • 4
  • 28
  • 59

2 Answers2

4

What the FreeNotification mechanism does is notifies registered components that this component is being freed. They then use their Notification method to ensure that they don't hold any references to it (which is what your example is doing) so that they don't end up with dangling references to an invalid object.

Mason Wheeler
  • 82,511
  • 50
  • 270
  • 477
  • Sure. But within the `SetupInternalLabel` function, the `FEditLabel` is created as child of `TCustomLabeledEdit` (`FEditLabel := TBoundLabel.Create(Self);`). So how that could cause dangling reference? I mean, how could I use the label, after destroying the LabeledEdit? – EProgrammerNotFound Apr 23 '14 at 19:02
  • If one try to access the label like `LabeledEdit1.EditLabel`, it will raise an AV because LabeledEdit1 it is already destroyed. – EProgrammerNotFound Apr 23 '14 at 19:04
  • 1
    You can safely free a nil reference, but you get an exception freeing a reference to an already destroyed instance. Another point is, you can check if assigned – Sir Rufo Apr 23 '14 at 19:09
  • @PageNotFound: If a non-nil reference exists, you can call things on it. If what's there is a destroyed object, you might get an access violation, or you might have something that seems to work, but actually ends up corrupting data. Undefined behavior is a really ugly thing. Better to nil the reference, and then if someone tries to use it, they're **guaranteed** to get an access violation, and one that's very easy to fix in a debugger. – Mason Wheeler Apr 23 '14 at 19:09
  • Yes. So that is it? Is this the whole purpose of FreeNotification? I was expecting something more magical. – EProgrammerNotFound Apr 23 '14 at 19:13
  • 1
    @MasonWheeler You should also mention the ownership part. The owner is responsible for the owned instances. And so it is necessary to inform the owner that it is no longer responsible for that – Sir Rufo Apr 23 '14 at 19:14
  • @SirRufo When the owner relinquishes the ownership? – EProgrammerNotFound Apr 23 '14 at 19:23
  • 3
    @PageNotFound When the owned component notifies the owner. This is initiated by calling `FreeNotification` and can be reworded: Notify me, if the instance I'm responsible for gets destroyed not initiated by me, so I can kick this instance from my ResponsibleFor list. Have a look at the source of `TComponent` (start with `constructor Create( Owner : TComponent );`) – Sir Rufo Apr 23 '14 at 20:04
  • 1
    @PageNotFound So `FreeNotification` belongs to that ownership handling of `TComponent`, but it is not limited to. – Sir Rufo Apr 23 '14 at 20:06
0

The point of FreeNotification is to allow you to clean up references to form children in cases where these components close and free themselves. In this example I use a Modal form, the FreeNotification sets the reference to NULL which allows me to detect if the form is still open or already exists if the user creates another one

void __fastcall TForm1::OpenForm(TObject *Sender)
{
    frmGetPrint = new TfrmGetPrint(Application);
    frmGetPrint->FreeNotification( this);
    frmGetPrint->Show();
}

frmGetPrint must free itself when closed:

void __fastcall TfrmSetPrint::FormClose(TObject *Sender, TCloseAction &Action)
{
    Action = caFree;
}

You need to create a function in the parent form referred to by this in the call to FreeNotification( this), in this case Form1

void __fastcall TForm1::Notification(Classes::TComponent* AComponent, 
Classes::TOperation Operation)
{
    if( AComponent == frmGetPrint && Operation == opRemove)
        frmGetPrint = NULL;
}
Gary Benade
  • 507
  • 4
  • 16