The inside of the component automatic clearance
We already know that Tcomponent will automatically remove all of its OWNS all Component when it is released, which is a great feature of the Delphi program. Otherwise, any dynamically generated objects such as Menu items must be maintained and deleted themselves, which will be. How does the VCL do this? It can be imagined that every Component should keep a list, record the Components it owns, and remove all objects in the list at the same time in its own destructure function. Basically this idea is correct, but it should be considered two possible situations: (1) When the component deletes itself, all the sub-components there is clear, and the sub-component is passive; (2) The sub-component is actively calling Free or Destroy. At this time, the parent member should have a way to get notifications and maintain the synchronization of the list. Otherwise, there may be a case where a sub-component is destructed more than two times, and the consequences can probably think of it.
To maintain the synchronization of the list, the sub-component must report to the parent component when it is created, and the parent component must be given to the parent component when exiting.
The principle is not complex, and now it is to see how the VCL is implemented. Tcomponent's constructor is called create, with a AOWNER parameter:
Constructor Tcomponent.create (Aowner: Tcomponent);
Begin
FComponentStyle: = [csinheritable];
If Aowner <> nil damponent (self);
END;
INSERTComponent is the place where we care. Looking for the specific implementation of it:
Procedure Tcomponent.insertComponent (ACOMPONENT: TComponent);
Begin
Acomponent.validateContainer (Self);
ValidateRename (Acomponent, '', Acomponent.fname);
INSERT (ACOMPONENT);
Acomponent.setReference (TRUE);
IF csdesigning in componentState Then
Acomponent.SetDesigning (TRUE);
NOTIFICATION (Acomponent, Opinsert);
END;
Although some places have not understood, but the key part appears to be insert (Acomponent). Find insert:
Procedure Tcomponent.Insert (Acomponent: Tcomponent);
Begin
IF fcomponents = nil the fcomponents: = TLIST.CREATE;
FComponents.Add (Acomponent);
Acomponent.fowner: = Self;
END;
The internal list we guess is finally appeared, it is a common, which can accommodate any TList type of TOBJECT or POINTER.
In addition, from the above code segment can also see a typical processing method in the VCL, that is, the object "is only established when needed", such as establishing the FComponents above belongs to this. Of course, check the validity of the FComponent once every time you create a component, you will affect the running speed of the program, but consider the memory occupied by the program (Form and Application generally have a historic list, and the general components are completely There is no need, if each component creates a list, then the memory occupied is considerable), this processing method also has its truth. Now let's take a look at the situation when destructure:
Destructor tComponent.destroy;
Begin
DESTROYING;
IF ffreenotifies <> nil dam
Begin
While Assigned (ffreenotifies) and (ffreenotifies.count> 0) DO
Tcomponent (ffreenotifies [ffreenotifies.count - 1]). NOTIFICATION (Self, Opremove);
Freeandnil (ffreenotifies);
END;
DESTROYComponents;
If FOWNER <> nil damponent (Self);
Inherited destroy;
END;
There are two important places here: (1) DestroyComponents, obviously delete its Components; (2) FOWNER.RemoveComponents (Self), it seems to remove itself from the parent component's FComponents list.
Procedure tComponent.destroyComponents;
VAR
Tcomponent;
Begin
While FComponents <> NIL DO
Begin
Instance: = fcomponents.last;
CSFreenotification in instance.fcomponentstate
OR (fcomponentstate * [csdesigning, csinline] = [csdesigning, csinline]) THEN
RemoveComponent (Instance)
Else
REMOVE (Instance);
Instance.destroy;
END;
END;
Procedure Tcomponent.removeComponent (ACOMPONENT: TComponent);
Begin
ValidateRename (ACOMPONENT, ACOMPONENT.FNAME, '');
Notification (ACOMPONENT, OPREMOVE);
ACOMPONENT.SETREFERENCE (FALSE);
REMOVE (ACOMPONENT);
END;
RemoveComponent calls REMOVE, then look at this function:
Procedure Tcomponent.remove (ACOMPONENT: TComponent);
Begin
Acomponent.fowner: = NIL;
FComponents.remove (ACOMPONENT);
IF fcomponents.count = 0 THEN
Begin
Fcomponents.free;
FComponents: = NIL;
END;
Very simple, is it? Through this travel, I believe that "I will be automatically cleared and how to be cleared in what the component is cleared", and I will have a clear answer later.
At note: Through the above example, I realize how convenient to the navigation keys in Delphi! Whether it is your own unit or the VCL internal unit, use Ctrl Click and Ctrl Shift Up / Down, and the Back / Forword button in the Code Editor can be positioned anywhere. There is no such convenient in Visual C , whether it is use Trace or uses Source Browser, it must be compiled first, even if you use Find in Files. Compared to the trace source code in Delphi is more convenient. Although Delphi's start-up speed is indeed slow, but it is still sure in other respects.