Go to the first, previous, next, last section, table of contents.
-
Three kinds of actions are fundamental to the manipulation of objects:
initialization, finalization, and assignment. Every object is
initialized, either explicitly or by default, after being created (for
example, by an object_declaration or allocator). Every object is
finalized before being destroyed (for example, by leaving a
subprogram_body containing an object_declaration, or by a call to an
instance of Unchecked_Deallocation). An assignment operation is used as
part of assignment_statements, explicit initialization, parameter
passing, and other operations.
-
Default definitions for these three fundamental operations are provided
by the language, but a controlled type gives the user additional control
over parts of these operations. In particular, the user can define, for
a controlled type, an Initialize procedure which is invoked immediately
after the normal default initialization of a controlled object, a
Finalize procedure which is invoked immediately before finalization of
any of the components of a controlled object, and an Adjust procedure
which is invoked as the last step of an assignment to a (nonlimited)
controlled object.
Static Semantics
-
The following language-defined library package exists:
-
package Ada.Finalization is
pragma Preelaborate(Finalization);
-
type Controlled is abstract tagged private;
-
procedure Initialize(Object : in out Controlled);
procedure Adjust (Object : in out Controlled);
procedure Finalize (Object : in out Controlled);
-
type Limited_Controlled is abstract tagged limited private;
-
procedure Initialize(Object : in out Limited_Controlled);
procedure Finalize (Object : in out Limited_Controlled);
private
... -- not specified by the language
end Ada.Finalization;
-
A controlled type is a descendant of Controlled or Limited_Controlled.
The (default) implementations of Initialize, Adjust, and Finalize have
no effect. The predefined "=" operator of type Controlled always returns
True, since this operator is incorporated into the implementation of the
predefined equality operator of types derived from Controlled, as
explained in See section 4.5.2 Relational Operators and Membership Tests. The type Limited_Controlled is like
Controlled, except that it is limited and it lacks the primitive
subprogram Adjust.
Dynamic Semantics
-
During the elaboration of an object_declaration, for every controlled
subcomponent of the object that is not assigned an initial value (as
defined in 3.3.1), Initialize is called on that subcomponent. Similarly,
if the object as a whole is controlled and is not assigned an initial
value, Initialize is called on the object. The same applies to the
evaluation of an allocator, as explained in See section 4.8 Allocators.
-
For an extension_aggregate whose ancestor_part is a subtype_mark,
Initialize is called on all controlled subcomponents of the ancestor
part; if the type of the ancestor part is itself controlled, the
Initialize procedure of the ancestor type is called, unless that
Initialize procedure is abstract.
-
Initialize and other initialization operations are done in an arbitrary
order, except as follows. Initialize is applied to an object after
initialization of its subcomponents, if any (including both implicit
initialization and Initialize calls). If an object has a component with
an access discriminant constrained by a per-object expression,
Initialize is applied to this component after any components that do not
have such discriminants. For an object with several components with such
a discriminant, Initialize is applied to them in order of their
component_declarations. For an allocator, any task activations follow
all calls on Initialize.
-
When a target object with any controlled parts is assigned a value,
either when created or in a subsequent assignment_statement, the
assignment operation proceeds as follows:
-
The value of the target becomes the assigned value.
-
The value of the target is adjusted.
-
To adjust the value of a (nonlimited) composite object, the values of
the components of the object are first adjusted in an arbitrary order,
and then, if the object is controlled, Adjust is called. Adjusting the
value of an elementary object has no effect, nor does adjusting the
value of a composite object with no controlled parts.
-
For an assignment_statement, after the name and expression have been
evaluated, and any conversion (including constraint checking) has been
done, an anonymous object is created, and the value is assigned into it;
that is, the assignment operation is applied. (Assignment includes value
adjustment.) The target of the assignment_statement is then finalized.
The value of the anonymous object is then assigned into the target of
the assignment_statement. Finally, the anonymous object is finalized. As
explained below, the implementation may eliminate the intermediate
anonymous object, so this description subsumes the one given in
See section 5.2 Assignment Statements.
Implementation Permissions
-
An implementation is allowed to relax the above rules (for nonlimited
controlled types) in the following ways:
-
For an assignment_statement that assigns to an object the value of that
same object, the implementation need not do anything.
-
For an assignment_statement for a noncontrolled type, the implementation
may finalize and assign each component of the variable separately
(rather than finalizing the entire variable and assigning the entire new
value) unless a discriminant of the variable is changed by the
assignment.
-
For an aggregate or function call whose value is assigned into a target
object, the implementation need not create a separate anonymous object
if it can safely create the value of the aggregate or function call
directly in the target object. Similarly, for an assignment_statement,
the implementation need not create an anonymous object if the value
being assigned is the result of evaluating a name denoting an object
(the source object) whose storage cannot overlap with the target. If the
source object might overlap with the target object, then the
implementation can avoid the need for an intermediary anonymous object
by exercising one of the above permissions and perform the assignment
one component at a time (for an overlapping array assignment), or not at
all (for an assignment where the target and the source of the assignment
are the same object). Even if an anonymous object is created, the
implementation may move its value to the target object as part of the
assignment without re-adjusting so long as the anonymous object has no
aliased subcomponents.
- 7.6.1: Completion and Finalization
Go to the first, previous, next, last section, table of contents.