Previous | Table of Contents | Next |
Line 7 declares a list variable; the type List is provided by HB.Dashboards. The variables Speed, Fuel, and so on, and their associated pointers SpeedPointer, FuelPointer, and so on, were declared in HB.Instruments.Aux. Lines 11-16 set the various display names; lines 18-23 set various values. Lines 25-30 build the dashboard by adding each of the pointer objects to the list. Finally, line 32 displays the entire dashboard as promised at the start of this discussion. The output, once again, is
Speed : 45 Miles per Hour Fuel : 60 % Water : <****************....> Oil : <******..............> Time : 12:15:00 Chronometer : <<79976>>
10.4.3.6. Comments on Pointers in Ada
In building the heterogeneous list, why must the nodes contain pointers to the instrument objects and not the objects themselves? That is, why must I instantiate with InstrumentPointer and not something more like InstrumentClass? The answer relates to storage allocation. A list node must have a component indicating its contained object; space must be allocated for this object, but how much? I do not know, and cannot know, the space required for each type in InstrumentClass because Instrument is an extensible type that allows types derived from it to grow indefinitely. On the other hand, pointers are the same size regardless of the size of their designated objects. Ada could have been designed so that these pointers were created implicitly, by the runtime system, but the designers chose to require explicit pointers, to accommodate real-time system designers who prefer not to have pointers generated behind their backs.
Why are Ada pointers called access objects? In other languages, pointer has been directly associated with address, and also the term acquired a negative reputation because pointers are so easily abused. In Ada, an access value has no direct relationship to an address. Access values and addresses may or may not have the same internal form; this is intentionally left up to the implementer. Further, no arithmetic operations are predefined on access values. This minimizes the likelihood that pointers will point to inappropriate memory locations.
Another important characteristic of Ada pointers is that each pointer object is guaranteed by the standard to have the initial value Null, a special value that denotes an empty pointer. An execution-time attempt to dereference a Null pointer results in Constraint_Error being raised. Automatic initialization of pointers ensures that uninitialized pointers containing garbage cannot be used to access unpredictable blocks of storage. This makes programs that use pointers inherently safer and also significantly easier to write and debug.
Finally, Ada rules require that any object accessed by Access have a lifetime at least as long as that of the corresponding general access type. This rule prevents a possible dangling pointer. For example, consider this short main program.
1 with HB.Instruments; use HB.Instruments; 2 with HB.Instruments.Basic; use HB.Instruments.Basic; 3 procedure Main is 4 type Pointer is access all Speedometer; 5 Pointer1: Pointer; 6 1begin 7 declare 8 Pointer2: Pointer; 9 S: aliased Speedometer; 10 begin 11 Pointer2 := SAccess; 12 Pointer1 := Pointer2; 13 end; 14 Pointer1.all.Value := 50; 15 end Main;
In the exception-handling example, you observed that you can create framesbegin/end blockswithin a program unit. In line 7, declare opens an inner frame that allows me to declare local entities whose lifetimes begin when their declarations are elaborated and end when control passes through the end of the frame. Local objects are typically stack-allocated, so their space is reclaimed at the end of the frame.
This example has a big problem: Pointer2 and S are allocated and reclaimed in the inner frame, but Pointer1 is not. This means that in line 14, Pointer1 is dangling and the statement will try to write a value into space that has already been reclaimed. Dangling pointers are usually not this obvious and can be horribly difficult to debug. Luckily, Ada programs such as this are invalid. The compiler rejects programs that use the Access attribute at a level deeper than the one in which the corresponding general access type is declared; this simple rule guarantees that no pointer of this kind can outlive its designated value.
Previous | Table of Contents | Next |