13.11.2 Unchecked Storage Deallocation
1
[
Unchecked
storage deallocation of an object designated by a value of an access
type is achieved by a call to an instance of the generic procedure Unchecked_Deallocation.]
Static Semantics
2
The following language-defined
generic library procedure exists:
3/3
{
AI05-0229-1}
generic
type Object(<>)
is limited private;
type Name
is access Object;
procedure Ada.Unchecked_Deallocation(X :
in out Name)
with Convention => Intrinsic;;
pragma Convention(Intrinsic, Ada.Unchecked_Deallocation);
pragma Preelaborate(Ada.Unchecked_Deallocation);
3.a/3
Reason: {
AI05-0229-1}
The
aspect pragma
Convention implies that the attribute Access is not allowed for instances
of Unchecked_Deallocation.
Legality Rules
3.1/3
{
AI05-0157-1}
A call on an instance of Unchecked_Deallocation
is illegal if the actual access type of the instance is a 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. 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.
3.b/3
Discussion: This
rule is the same as the rule for allocators.
We could have left the last sentence out, as a call to Unchecked_Deallocation
cannot occur in a specification as it is a procedure call, but we left
it for consistency and to avoid future maintenance hazards.
Dynamic Semantics
4
Given an instance of
Unchecked_Deallocation declared as follows:
5
procedure Free is
new Ada.Unchecked_Deallocation(
object_subtype_name, access_to_variable_subtype_name);
6
Procedure Free has
the following effect:
7
1.
After executing Free(X), the value of X is null.
8
2.
Free(X), when X is already equal to null, has no effect.
9/3
3.
{
AI95-00416-01}
{
AI05-0107-1}
Free(X), when X is not equal to
null first performs finalization
of the object designated by X (and any coextensions of the object —
see 3.10.2), as described in
7.6.1 7.6.
It then deallocates the storage occupied by the object designated by
X
(and any coextensions). If the storage
pool is a user-defined object, then the storage is deallocated by calling
Deallocate
as described in 13.11,
passing access_to_variable_subtype_name'Storage_Pool as the Pool
parameter. Storage_Address is the value returned in the Storage_Address
parameter of the corresponding Allocate call. Size_In_Storage_Elements
and Alignment are the same values passed to the corresponding Allocate
call. There is one exception: if the object being freed contains
tasks, the object might not be deallocated.
9.a/3
Ramification: {
AI05-0107-1}
Free calls only the specified Deallocate procedure to do deallocation.
For any given object deallocation, the number of calls to Free (usually
one) will be equal to the number of Allocate calls it took to allocate
the object. We do not define the relative order of multiple calls used
to deallocate the same object — that is, if the allocator
allocated two pieces x and y, then Free might deallocate
x and then y, or it might deallocate y and then
x.
10/2
{
AI95-00416-01}
After
Free(X), the object designated by X, and any subcomponents
(and
coextensions) thereof, no longer exist; their storage can be reused
for other purposes.
Bounded (Run-Time) Errors
11
It
is a bounded error to free a discriminated, unterminated task object.
The possible consequences are:
11.a
Reason: This is an error because the
task might refer to its discriminants, and the discriminants might be
deallocated by freeing the task object.
12
No exception is raised.
13
Program_Error
or Tasking_Error is raised at the point of the deallocation.
14
Program_Error
or Tasking_Error is raised in the task the next time it references any
of the discriminants.
14.a
Implementation Note: This last case presumes
an implementation where the task references its discriminants indirectly,
and the pointer is nulled out when the task object is deallocated.
15
In the first two cases, the storage for the discriminants
(and for any enclosing object if it is designated by an access discriminant
of the task) is not reclaimed prior to task termination.
15.a
Ramification: The storage might never
be reclaimed.
Erroneous Execution
16/3
{
AI05-0033-1}
{
AI05-0262-1}
Evaluating a name that denotes
a nonexistent object
, or a protected subprogram
or subprogram renaming whose associated object (if any) is nonexistent,
is erroneous. The execution of a call to an instance of Unchecked_Deallocation
is erroneous if the object was created other than by an
allocator
for an access type whose pool is Name'Storage_Pool.
16.a/3
Reason: {
AI05-0033-1}
{
AI05-0262-1}
The part about a protected subprogram is intended
to cover the case of an access-to-protected-subprogram where the associated
object has been deallocated. The part about a subprogram renaming is
intended to cover the case of a renaming of a prefixed view where the
prefix object has been deallocated, or the case of a renaming of an entry
or protected subprogram where the associated task or protected object
has been deallocated.
16.b/3
Ramification: {
AI05-0157-1}
This text does not cover the case of a name that
contains a null access value, as null does not denote an object
(rather than denoting a nonexistent object).
Implementation Advice
17
For a standard storage pool, Free should actually
reclaim the storage.
17.a.1/2
Implementation Advice:
For a standard storage pool, an instance
of Unchecked_Deallocation should actually reclaim the storage.
17.a/2
Ramification: {
AI95-00114-01}
This is not a testable property, since we do not
know
how much storage is used by a given pool element, nor whether
fragmentation can occur.
17.1/3
{
AI05-0157-1}
A call on an instance of Unchecked_Deallocation
with a non-null access value should raise Program_Error if the actual
access type of the instance is a type for which the Storage_Size has
been specified to be zero or is defined by the language to be zero.
17.a.1/3
Implementation Advice:
A call on an instance of Unchecked_Deallocation
with a non-null access value should raise Program_Error if the actual
access type of the instance is a type for which the Storage_Size has
been specified to be zero or is defined by the language to be zero.
17.b
Discussion: If
the call is not illegal (as in a generic body), we recommend that it
raise Program_Error. Since the execution of this call is erroneous (any
allocator from the pool will have raised Storage_Error, so the non-null
access value must have been allocated from a different pool or be a stack-allocated
object), we can't require any behavior — anything at all would
be a legitimate implementation.
18
31 The rules here that refer to Free apply
to any instance of Unchecked_Deallocation.
19
32 Unchecked_Deallocation cannot be instantiated
for an access-to-constant type. This is implied by the rules of
12.5.4.
Wording Changes from Ada 95
19.a/2
{
AI95-00416-01}
The rules for coextensions are clarified (mainly
by adding that term). In theory, this reflects no change from Ada 95
(coextensions existed in Ada 95, they just didn't have a name).
Wording Changes from Ada 2005
19.b/3
{
AI05-0033-1}
Correction: Added a rule that using an access-to-protected-subprogram
is erroneous if the associated object no longer exists. It is hard to
imagine an alternative meaning here, and this has no effect on correct
programs.
19.c/3
{
AI05-0107-1}
Correction: Moved the requirements on an
implementation-generated call to Deallocate to 13.11,
in order to put all of the rules associated with implementation-generated
calls to Allocate and Deallocate together.
19.d/3
{
AI05-0157-1}
Correction: Added wording so that calling
an instance of Unchecked_Deallocation is treated similarly to allocators
for access types where allocators
would be banned.
Ada 2005 and 2012 Editions sponsored in part by Ada-Europe