In this section... 5.4.1 Heterogeneous Data 5.4.2 Nested Records 5.4.3 Dynamic Data |
Summary of Guidelines from this section |
type Propulsion_Method is (Sail, Diesel, Nuclear); type Craft is record Name : Common_Name; Plant : Propulsion_Method; Length : Feet; Beam : Feet; Draft : Feet; end record; type Fleet is array (1 .. Fleet_Size) of Craft; |
The idea is to put the information a maintainer needs to know where it can be
found with the minimum of effort. For example, if all information relating to
a given Craft
is in the same place, the relationship is clear both in the
declarations and especially in the code accessing and updating that
information. But, if it is scattered among several data structures, it is less
obvious that this is an intended relationship as opposed to a coincidental
one. In the latter case, the declarations may be grouped together to imply
intent, but it may not be possible to group the accessing and updating code
that way. Ensuring the use of the same index to access the corresponding
element in each of several parallel arrays is difficult if the accesses are at
all scattered.
If the application must interface directly to hardware, the use of records, especially in conjunction with record representation clauses, could be useful to map onto the layout of the hardware in question.
Language Ref Manual references: 3.7 Record Types, F Implementation-Dependent Characteristics
type Coordinate is record Row : Local_Float; Column : Local_Float; end record; type Window is record Top_Left : Coordinate; Bottom_Right : Coordinate; end record; |
if Window1.Bottom_Right.Row > Window2.Top_Left.Row then . . . |
Language Ref Manual references: 3.7 Record Types
Storage_Error
.
P1 := new Object; P2 := P1; Unchecked_Object_Deallocation(P2); |
This line can raise an exception due to referencing the deallocated object:
X := P1.all; |
In the following three lines, if there is no intervening assignment of the
value of P1
to any other pointer, the object created on the first line is no
longer accessible after the third line. The only pointer to the allocated
object has been dropped.
P1 := new Object; ... P1 := P2; |
A dropped pointer depends on an implicit memory manager for reclamation of space. It also raises questions for the reader as to whether the loss of access to the object was intended or accidental.
An Ada environment is not required to provide deallocation of dynamically
allocated objects. If provided, it may be provided implicitly (objects are
deallocated when their access type goes out of scope), explicitly (objects are
deallocated when Unchecked_Deallocation
is called), or both. To increase the
likelihood of the storage space being reclaimed, it is best to call
Unchecked_Deallocation
explicitly for each dynamically object when you are
finished using it. Calls to Unchecked_Deallocation
also document a deliberate
decision to abandon an object, making the code easier to read and understand.
To be absolutely certain that space is reclaimed and reused, manage your own
"free list." Keep track of which objects you are finished with, and reuse them
instead of dynamically allocating new objects later.
The dangers of dangling references are that you may attempt to use them, thereby accessing memory which you have released to the memory manager, and which may have been subsequently allocated for another purpose in another part of your program. When you read from such memory, unexpected errors may occur because the other part of your program may have previously written totally unrelated data there. Even worse, when you write to such memory you can cause errors in an apparently unrelated part of the code by changing values of variables dynamically allocated by that code. This type of error can be very difficult to find. Finally, such errors may be triggered in parts of your environment that you didn't write, for example, in the memory management system itself which may dynamically allocate memory to keep records about your dynamically allocated memory.
Keep in mind that any uninitialized or unreset component of a record or array can also be a dangling reference or carry a bit pattern representing inconsistent data.
Whenever you use dynamic allocation it is possible to run out of space. Ada
provides a facility (a length clause) for requesting the size of the pool of
allocation space at compile time. Anticipate that you can still run out at run
time. Prepare handlers for the exception Storage_Error
, and consider carefully
what alternatives you may be able to include in the program for each such
situation.
There is a school of thought that dictates avoidance of all dynamic
allocation. It is largely based on the fear of running out of memory during
execution. Facilities such as length clauses and exception handlers for
Storage_Error
provide explicit control over memory partitioning and error
recovery, making this fear unfounded.
Language Ref Manual references: 3.7 Record Types, 3.8 Access Types, 3.8.1 Incomplete Type Declarations, 4.8 Allocators, 11.1 Exception Declarations, 13.2 Length Clauses, 13.10.1 Unchecked Storage Deallocation