4.8 Allocators
[The evaluation of an
allocator
creates an object and yields an access value that designates the object.
{new: See allocator} {malloc:
See allocator} {heap
management: See also allocator} ]
Syntax
Name Resolution Rules
Legality Rules
Ramification: For example, ... new
S'Class ... (with no initialization expression) is illegal, but ... new
S'Class'(X) ... is legal, and takes its tag and constraints from the
initial value X. (Note that the former case cannot have a constraint.)
Reason: This prevents the allocated object
from outliving its type.
Reason: This prevents the allocated object
from outliving its discriminants.
{
AI95-00366-01}
An
allocator
shall not be of an access type for which the Storage_Size has been specified
by a static expression with value zero or is defined by the language
to be zero.
{generic contract issue
[partial]} In addition to the places where
Legality Rules normally apply (see
12.3),
this rule applies also in the private part of an instance of a generic
unit. This rule does not apply in the body of a generic unit or within
a body declared within the declarative region of a generic unit, if the
type of the allocator is a descendant of a formal access type declared
within the formal part of the generic unit.
Reason: An
allocator
for an access type that has Storage_Size specified to be zero is required
to raise Storage_Error anyway. It's better to detect the error at compile-time,
as the
allocator
might be executed infrequently. This also simplifies the rules for Pure
units, where we do not want to allow any allocators for library-level
access types, as they would represent state.
The last sentence covers the case of children
of generics, and formal access types of formal packages of the generic
unit.
Static Semantics
{
AI95-00363-01}
If the designated type of the type of the
allocator
is elementary, then the subtype of the created object is the designated
subtype. If the designated type is composite, then the subtype of the
created object is the designated subtype when the designated subtype
is constrained or there is a partial view of the designated type that
is constrained; otherwise, the created object is constrained by its initial
value [(even if the designated subtype is unconstrained with defaults)].
{constrained by its initial value
[partial]}
Discussion: See AI83-00331.
Reason: {
AI95-00363-01}
All objects created by an
allocator
are aliased, and most aliased composite objects need to be constrained
so that access subtypes work reasonably. Problematic access subtypes
are prohibited for types with a constrained partial view.
Discussion: {
AI95-00363-01}
If there is a constrained partial view of the type, this allows the objects
to be unconstrained. This eliminates privacy breaking (we don't want
the objects to act differently simply because they're allocated). Such
a created object is effectively constrained by its initial value if the
access type is an access-to-constant type, or the designated type is
limited (in all views), but we don't need to state that here. It is implicit
in other rules. Note, however, that a value of an access-to-constant
type can designate a variable object via 'Access or conversion, and the
variable object might be assigned by some other access path, and that
assignment might alter the discriminants.
Dynamic Semantics
{
AI95-00373-01}
{evaluation (allocator) [partial]}
For the evaluation of an initialized allocator, the
evaluation of the
qualified_expression
is performed first.
{evaluation (initialized
allocator) [partial]} {assignment
operation (during evaluation of an initialized allocator)}
An object of the designated type is created and the
value of the
qualified_expression
is converted to the designated subtype and assigned to the object.
{implicit
subtype conversion (initialization expression of allocator) [partial]}
Ramification: The conversion might raise
Constraint_Error.
{evaluation (uninitialized
allocator) [partial]} For the evaluation
of an uninitialized allocator, the elaboration of the
subtype_indication
is performed first. Then:
{
AI95-00373-01}
{assignment operation (during evaluation
of an uninitialized allocator)} If the
designated type is elementary, an object of the designated subtype is
created and any implicit initial value is assigned;
{
8652/0002}
{
AI95-00171-01}
{
AI95-00373-01}
If the designated type is composite, an object of the designated type
is created with tag, if any, determined by the
subtype_mark
of the
subtype_indication.
This object is then initialized by default (see
3.3.1)
using the
subtype_indication
to determine its nominal subtype.
{Index_Check
[partial]} {check,
language-defined (Index_Check)} {Discriminant_Check
[partial]} {check,
language-defined (Discriminant_Check)} A
check is made that the value of the object belongs to the designated
subtype.
{Constraint_Error (raised by
failure of run-time check)} Constraint_Error
is raised if this check fails. This check and the initialization of the
object are performed in an arbitrary order.
Discussion: AI83-00150.
{
AI95-00344-01}
{
AI95-00416-01}
For any
allocator,
if the designated type of the type of the
allocator
is class-wide, then a check is made that the accessibility level of the
type determined by the
subtype_indication,
or by the tag of the value of the
qualified_expression,
is not deeper than that of the type of the
allocator.
If the designated subtype of the
allocator
has one or more unconstrained access discriminants, then a check is made
that the accessibility level of the anonymous access type of each access
discriminant is not deeper than that of the type of the
allocator.
Program_Error is raised if either such check fails.
{Accessibility_Check
[partial]} {check,
language-defined (Accessibility_Check)} {Program_Error
(raised by failure of run-time check)}
Reason: {
AI95-00344-01}
The accessibility check on class-wide types prevents the allocated object
from outliving its type. We need the run-time check in instance bodies,
or when the type of the
qualified_expression
is class-wide (other cases are statically detected).
{
AI95-00416-01}
The accessibility check on access discriminants prevents the allocated
object from outliving its discriminants.
{
AI95-00280-01}
If the object to be created by an
allocator
has a controlled or protected part, and the finalization of the collection
of the type of the
allocator
(see
7.6.1) has started, Program_Error is
raised.
{Allocation_Check [partial]}
{check, language-defined
(Allocation_Check)} {Program_Error
(raised by failure of run-time check)}
Reason: If the object has a controlled
or protected part, its finalization is likely to be non-trivial. If the
allocation was allowed, we could not know whether the finalization would
actually be performed. That would be dangerous to otherwise safe abstractions,
so we mandate a check here. On the other hand, if the finalization of
the object will be trivial, we do not require (but allow) the check,
as no real harm could come from late allocation.
Discussion: This check can only fail
if an
allocator
is evaluated in code reached from a Finalize routine for a type declared
in the same master. That's highly unlikely; Finalize routines are much
more likely to be deallocating objects than allocating them.
{
AI95-00280-01}
If the object to be created by an
allocator
contains any tasks, and the master of the type of the
allocator
is completed, and all of the dependent tasks of the master are terminated
(see
9.3), then Program_Error is raised.
{Allocation_Check
[partial]} {check,
language-defined (Allocation_Check)} {Program_Error
(raised by failure of run-time check)}
Reason: A task created after waiting
for tasks has finished could depend on freed data structures, and certainly
would never be awaited.
[If the created object contains any tasks, they are
activated (see
9.2).] Finally, an access value
that designates the created object is returned.
Bounded (Run-Time) Errors
{
AI95-00280-01}
{bounded error (cause) [partial]}
It is a bounded error if the finalization of the
collection of the type (see
7.6.1) of the
allocator
has started. If the error is detected, Program_Error is raised. Otherwise,
the allocation proceeds normally.
Discussion: This check is required in
some cases; see above.
23 Allocators cannot create objects of
an abstract type. See
3.9.3.
24 If any part of the created object is
controlled, the initialization includes calls on corresponding Initialize
or Adjust procedures. See
7.6.
25 As explained in
13.11,
“
Storage Management”, the storage
for an object allocated by an
allocator
comes from a storage pool (possibly user defined).
{Storage_Error
(raised by failure of run-time check)} The
exception Storage_Error is raised by an
allocator
if there is not enough storage. Instances of Unchecked_Deallocation may
be used to explicitly reclaim storage.
26 Implementations are permitted, but not
required, to provide garbage collection (see
13.11.3).
Discussion: By default, the implementation
provides the storage pool. The user may exercise more control over storage
management by associating a user-defined pool with an access type.
Examples
Examples of allocators:
new Cell'(0,
null,
null)
-- initialized explicitly, see 3.10.1
new Cell'(Value => 0, Succ =>
null, Pred =>
null)
-- initialized explicitly
new Cell
-- not initialized
new Matrix(1 .. 10, 1 .. 20) -- the bounds only are given
new Matrix'(1 .. 10 => (1 .. 20 => 0.0)) -- initialized explicitly
new Buffer(100) -- the discriminant only is given
new Buffer'(Size => 80, Pos => 0, Value => (1 .. 80 => 'A')) -- initialized explicitly
Expr_Ptr'(
new Literal)
-- allocator for access-to-class-wide type, see 3.9.1
Expr_Ptr'(
new Literal'(Expression
with 3.5))
-- initialized explicitly
Incompatibilities With Ada 83
{
incompatibilities with Ada 83}
The
subtype_indication
of an uninitialized allocator may not have an explicit
constraint
if the designated type is an access type. In Ada 83, this was permitted
even though the
constraint
had no effect on the subtype of the created object.
Extensions to Ada 83
{
extensions to Ada 83}
Allocators
creating objects of type
T are now overloaded on access types
designating
T'Class and all class-wide types that cover
T.
Implicit array subtype conversion (sliding)
is now performed as part of an initialized allocator.
Wording Changes from Ada 83
We have used a new organization, inspired by
the ACID document, that makes it clearer what is the subtype of the created
object, and what subtype conversions take place.
Discussion of storage management issues, such
as garbage collection and the raising of Storage_Error, has been moved
to
13.11, “
Storage
Management”.
Inconsistencies With Ada 95
{
AI95-00363-01}
{
inconsistencies with Ada 95}
If the designated
type has a constrained partial view, the allocated object can be unconstrained.
This might cause the object to take up a different amount of memory,
and might cause the operations to work where they previously would have
raised Constraint_Error. It's unlikely that the latter would actually
matter in a real program (Constraint_Error usually indicates a bug that
would be fixed, not left in a program.) The former might cause Storage_Error
to be raised at a different time than in an Ada 95 program.
Incompatibilities With Ada 95
{
AI95-00366-01}
{
incompatibilities with Ada 95}
An
allocator
for an access type that has Storage_Size specified to be zero is now
illegal. Ada 95 allowed the
allocator,
but it had to raise Storage_Error if executed. The primary impact of
this change should be to detect bugs.
Extensions to Ada 95
{
8652/0010}
{
AI95-00127-01}
{
extensions to Ada 95}
Corrigendum:
An
allocator
can be a controlling parameter of a dispatching call. This was an oversight
in Ada 95.
Wording Changes from Ada 95
{
8652/0002}
{
AI95-00171-01}
Corrigendum: Clarified the elaboration of per-object constraints
for an uninitialized allocator.
{
AI95-00280-01}
Program_Error is now raised if the
allocator
occurs after the finalization of the collection or the waiting for tasks.
This is not listed as an incompatibility as the Ada 95 behavior was unspecified,
and Ada 95 implementations tend to generate programs that crash in this
case.
{
AI95-00344-01}
Added accessibility checks to class-wide
allocators.
These checks could not fail in Ada 95 (as all of the designated types
had to be declared at the same level, so the access type would necessarily
have been at the same level or more nested than the type of allocated
object).
{
AI95-00373-01}
Revised the description of evaluation of uninitialized allocators to
use “initialized by default” so that the ordering requirements
are the same for all kinds of objects that are default-initialized.
{
AI95-00416-01}
Added accessibility checks to access discriminants of
allocators.
These checks could not fail in Ada 95 as the discriminants always have
the accessibility of the object.