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
[editar]Por ejemplo, se puede definir un puntero a un tipo entero de esta manera:
typePEnteroisaccessInteger;
En un ejemplo con registros:
declaretypeTBúferisrecordMensaje: String(1..4); Prioridad: Integer;endrecord;typePTBúferisaccessTBúfer; Mensaje1, Mensaje2: PTBúfer;beginMensaje1 :=newTBúfer;-- Se crea un objeto de tipo TBúfer.Mensaje2 :=newTBú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.typeTNodoÁrbolBinario;-- Se declara después.typePTNodoÁrbolBinarioisaccessTNodoÁrbolBinario;typeTNodoÁrbolBinarioisrecordRamaIzda: PTNodoÁrbolBinario; Dato: Float; RamaDcha: PTNodoÁrbolBinario;endrecord; ÁrbolBinario: PTNodoÁrbolBinario;begin-- Se crea la raíz del árbol binario.ÁrbolBinario :=newTNodoÁrbolBinario'(null, 1.0,null);end;
Liberación de memoria
[editar]Cuando 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:
withAda.Unchecked_Deallocation;procedureEjemplo_Liberar_MemoriaistypeTVectorisarray(Integerrange<>)ofFloat;typePVectorisaccessTVector; PV: PVector;procedureLiberar_VectorisnewAda.Unchecked_Deallocation (TVector, PVector);beginPV :=newTVector(1..10); PV.all:= (others => 0.0);-- ...Liberar_Vector (PV);-- La memoria es liberada y PV es ahora nullendEjemplo_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.