13.11.2 Unchecked Storage Deallocation
[
{unchecked storage
deallocation} {storage
deallocation (unchecked)} {deallocation
of storage} {reclamation
of storage} {freeing
storage} 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
The following language-defined
generic library procedure exists:
generic
type Object(<>)
is limited private;
type Name
is access Object;
procedure Ada.Unchecked_Deallocation(X :
in out Name);
pragma Convention(Intrinsic, Ada.Unchecked_Deallocation);
pragma Preelaborate(Ada.Unchecked_Deallocation);
Reason: The
pragma
Convention implies that the attribute Access is not allowed for instances
of Unchecked_Deallocation.
Dynamic Semantics
Given an instance of
Unchecked_Deallocation declared as follows:
procedure Free is
new Ada.Unchecked_Deallocation(
object_subtype_name, access_to_variable_subtype_name);
Procedure Free has
the following effect:
1.
After executing Free(X), the value of X is null.
2.
Free(X), when X is already equal to null, has no effect.
3.
{
AI95-00416-01}
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.
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, 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.
Ramification: 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.
{
AI95-00416-01}
{freed: See nonexistent} {nonexistent}
{exist (cease to)
[partial]} {cease
to exist (object) [partial]} 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
{bounded
error (cause) [partial]} It is a bounded
error to free a discriminated, unterminated task object. The possible
consequences are:
Reason: This is an error because the
task might refer to its discriminants, and the discriminants might be
deallocated by freeing the task object.
No exception is raised.
{Program_Error
(raised by failure of run-time check)} {Tasking_Error
(raised by failure of run-time check)} Program_Error
or Tasking_Error is raised at the point of the deallocation.
{Program_Error
(raised by failure of run-time check)} {Tasking_Error
(raised by failure of run-time check)} Program_Error
or Tasking_Error is raised in the task the next time it references any
of the discriminants.
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.
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.
Ramification: The storage might never
be reclaimed.
Erroneous Execution
{nonexistent}
{erroneous execution
(cause) [partial]} Evaluating a name that
denotes a nonexistent object 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.
Implementation Advice
For a standard storage pool, Free should actually
reclaim the storage.
Implementation Advice: For a standard
storage pool, an instance of Unchecked_Deallocation should actually reclaim
the storage.
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.
27 The rules here that refer to Free apply
to any instance of Unchecked_Deallocation.
28 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
{
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).