Programación en Ada/Tipos/Punteros a objetos
Un nombre está ligado a un objeto desde su declaración hasta que el flujo del programa deja la unidad que contenía su declaración. Sin embargo, los punteros o apuntadores (access) proporcionan acceso a otros objetos, que se pueden crear y destruir dinámicamente.
El nombre de access en vez del habitual pointer se debe a que al diseñar Ada se quería huir de la mala fama que los punteros habían creado gracias a lenguajes como C, en los que se puede usar los punteros de manera muy insegura. Los tipos acceso de Ada son más seguros entre otras cosas porque no existe la aritmética de punteros, especialmente peligrosa. Además el uso de punteros en Ada es prescindible en muchas más situaciones que en C.
Las variables de tipo puntero en Ada se inicializan implícitamente a null.
Ejemplos
editarPor ejemplo, se puede definir un puntero a un tipo entero de esta manera:
type
PEnterois
access
Integer;
En un ejemplo con registros:
declare
type
TBúferis
record
Mensaje: String(1..4); Prioridad: Integer;end
record
;type
PTBúferis
access
TBúfer; Mensaje1, Mensaje2: PTBúfer;begin
Mensaje1 :=new
TBúfer;-- Se crea un objeto de tipo TBúfer.
Mensaje2 :=new
TBúfer'(Prioridad => 2, Mensaje =>"Hola"
);-- Con all se puede desreferenciar el puntero.
-- Mensaje1 es un puntero y Mensaje1.all es el registro.
Mensaje1.all
.Prioridad := 3;-- Sin embargo, al acceder a campos del registro la desreferenciación
-- puede hacerse implícita y .all es opcional en esos casos:
Mensaje1.Prioridad := 3;end
;
Es útil para implementar listas, colas, árboles y grafos. Por ejemplo:
declare
-- TNodoÁrbolBinario se necesita para definir el puntero.
type
TNodoÁrbolBinario;-- Se declara después.
type
PTNodoÁrbolBinariois
access
TNodoÁrbolBinario;type
TNodoÁrbolBinariois
record
RamaIzda: PTNodoÁrbolBinario; Dato: Float; RamaDcha: PTNodoÁrbolBinario;end
record
; ÁrbolBinario: PTNodoÁrbolBinario;begin
-- Se crea la raíz del árbol binario.
ÁrbolBinario :=new
TNodoÁrbolBinario'(null
, 1.0,null
);end
;
Liberación de memoria
editarCuando se quiera liberar la memoria dinámicamente, hay que hacer uso del procedimiento genérico Ada.Unchecked_Deallocation [1], el cual se instancia con los tipos de objeto y de puntero, y se le llama pasándole punteros. Por ejemplo:
with
Ada.Unchecked_Deallocation;procedure
Ejemplo_Liberar_Memoriais
type
TVectoris
array
(Integerrange
<>)of
Float;type
PVectoris
access
TVector; PV: PVector;procedure
Liberar_Vectoris
new
Ada.Unchecked_Deallocation (TVector, PVector);begin
PV :=new
TVector(1..10); PV.all
:= (others => 0.0);-- ...
Liberar_Vector (PV);-- La memoria es liberada y PV es ahora null
end
Ejemplo_Liberar_Memoria;
El nombre de Unchecked_Deallocation viene del hecho de que no hay comprobación de que no queden punteros colgantes (dangling pointers), es decir que si se ha copiado el puntero en otra variable, después de llamar a Liberar_Vector el puntero copia está apuntando a una dirección de memoria no reservada y los efectos son imprevisibles, puesto que se puede haber reservado y se pude escribir o leer memoria que ya no pertenece a ese objeto.
Este sistema es similar al de C++ con new y delete. Un sistema de recolección de basura similar al de Java está previsto en el estándar, pero ningún compilador de Ada hasta el momento lo proporciona. Esto es debido a que aunque es un mecanismo más seguro, es menos eficiente y puede ser un problema para los sistemas de tiempo real por su impredictibilidad.
En Ada 95 existen métodos de gestión de memoria más seguros que el uso directo de Unchecked_Deallocation basados en los tipos controlados, algo semejante a lo que se consigue en C++ con constructores y destructores que manejan memoria dinámica.