B. Access types & Pointers - JulTob/Ada GitHub Wiki

Access types are dangerous

  • Multiple memory issues
  • Leaks / corruptions

  • Introduces potential random failures that are complicated to analyze
  • Increase the complexity of the data structures
  • May decrease the performance of the application
  • Dereferences are slightly more expensive than direct access

  • Allocations are a lot more expensive than stacking objects

  • Ada avoids the use of addresses as much as possible
  • Arrays are not pointers

  • Parameters are implicitly passed by reference

  • Only use them when needed

Access types Pointers

An access is just like an address. You can say the house at the address '13 Paper Street' instead of having to show the actual house. Just like humans live in houses, data objects live in memory spaces.

type Integer_Access is access Integer;
 -- Storage pool access type
 IntA: Integer_Access := new Integer;
 IntA0: Integer_Access := new Integer'(0);
...
  IntA.all := 3;
  -- Int allocates a 3
  Integer_Text_IO.Put(Int.all);       

Pools

Any pool

type T is […]
type T_Access is access all T;
V : T_Access := new T;

Pool Spcific

Not all

type T is […]
type T_Access is access T;
V : T_Access := new T;

An access-type is used to dynamically create objects during execution.

Note for C(++): Access types are like pointers.
An access value provides the location of an object which has been created by an allocator.

Access objects are used to call other objects by reference. In the same ways the web page URL, or the house address, allows access to the web page or the house. It is like referring to a book’s chapter by its page number.

Ada access types must explicitly indicate the type of data to which they refer.

x : aliased float;
px : access float := x'access;

Declaring a variable as aliased means it can be referenced by its access. Just like the city's government assigns a house an address, aliasing asks the computer's government (the Operating System) to assign this variable an address, so it may send letters to it.

THIS MEANS THE OBJECT RESIDES IN MEMORY (not in registers, or optimized out of the program).

The postman has to know how to go to a house, in the same way, an access type has to know to search in memory. To differentiate from register access variables, who build their own objects in registers, the type has to be declared as access all.

To access a constant, meaning the value accessed will not change, is best to declare as access constant.

type Integer_Access is access all Integer;
Var: aliased Integer;
Ptr: Intege_Access := Var'Access;
Cons: Constant Integer := 3.14;
Pass: access constant := Cons'Access;

Similar to pointers, accesses differ in that accessibility is checked beforehand. Objects out of scope will not be able to be accessed.

THIS PREVENTS MEMORY LEAKS

You can, theoretically, produce a program with memory leaks in Ada, but you have to go really far out of the way to make it so.



Handle: access Buffer_type;
                    
...
Handle := new Buffer_Type; --Allocates a new buffer in the storage pool 
Handle.Start := 1; --We can refer to the buffer’s  components indirectly
Handle.all := My_Buffer; --All refers to the complete record
Handle.Start = Handle.all.Start;
-- Always True. Strictly speaking, an abbreviation
Type Cell is
  record
    Next: access Cell;
    Value: Data;
end record
Type Cell;   --Pre-Declaration;
Type Cell_Ptr is access Cell;
Type Cell is
  record
    Next: access Cell;
    Value: Data;
end record
...
List.Next := new Cell;

Access types often refer to record types as in these examples but can refer to any type. Access types may also be used to refer to subprograms and this is particularly important for certain repetitive operations and when communicating with programs in other languages.

procedure ReadBuffer(Buffer: Buffer_Type) is  --Size?
   for b in Buffer’Range is
...
      Buffer’First;
      Buffer’Last;
...
Type Buffer_Type is array (Integer  range <>) of Character;
...
B1: Buffer_Type ( 0 .. 15); 
B2: Buffer_Type ( 1 .. 16);
B3: Buffer_Type ( 16 .. 32);
...
B1 := B2; --Works because it's the same length
...
procedure Process_Buffer (Buffer : in Buffer_Type) is
begin
for I in Buffer’Range loop
 --Buffer(I);
end loop;
end Process_Buffer ;
...
I := B1’First; --is 0, First Index
I := B2’Last;  --is 16, Last Index
Type String is array (Positive range <>) of Character;
--Indefinite length

These pointers can be used to point to a variable that is a limited type or an object that is dynamically allocated on the heap, assuming that the object is very large and making multiple copies of it either cannot be done or is not recommended.

The main difference to pointers is that you cannot do arithmetics to an Access. You cannot go beyond it's intended space, just as you can't go to a page on the next book by keep reading after you finish a book.

This prevents memory leaks altogether.

with Ada.Text_IO;
use Ada.Text_IO;

procedure TestAccess is

  type Int_Access is access Integer;
  -- type Int_Access is access all Integer;


  int: Int_access;
  alint: aliased Integer := 12;
  --procedure Deallocate is new Ada.Unchecked_Deallocation( int, Int_Access);

  begin

    int:= new Integer'(7);


    --  Deallocate(int);
    int:= alint'Access;


    Put(Integer'Image(int.all));
    Put(Integer'Image(alint));
    end TestAccess;

Test_Int : aliased Integer := 94; --  Test_Int variable is aliased.

Making a variable aliased tells the compiler that this value needs to be in RAM because later on you would like to get a pointer aimed at its value. In effect, this will prevent the variable from being assigned to a register in your CPU since its access type is what we are after.

Allocator

An allocator creates a new object of an access type, and returns an access value designating the location of a created object.

with Creatures; Use Creatures;
procedure Creatures_Test is 
      Type OrcRef IS Access Orc;
      Enemy_Orc : OrcRef;
  begin
     Enemy_Orc:= new Orc;
     Enemy_Orc.all := Make(80)
     Enemy_Orc.Health;
  end Creatures_Test;
Punt1, Punt2 : access Integer;

--  Allocators
Punt1 := new Integer;      --  subtype_indication
Punt2 := new Integer'(10); --  qualified_expression

Null Values

A pointer that does not point to any actual data has a null value

Without an initialization, a pointer is null by default

null can be used in assignments and comparisons

   type Acc is access all Integer;

   V : Acc;
begin
   if V = null then
      --  will go here
   end if

   V := new Integer'(0);
   V := null; --  semantically correct, but introduces a leak

Allocation

Objects are created with the “new” reserved word.

The created object must be constrained with the constraint given during the allocation

The object can be created by copying an existing object – using a qualifier

V : String_Access := new String (1 .. 10);

V : String_Access := new String'("This is a String");

Deallocation

with Ada.Unchecked_Deallocation;
-- dependency on the
generic subprogram

procedure P is
   type An_Access is access all A_Type;

   procedure Free is new Ada.Unchecked_Deallocation (A_Type, An_Access);
   -- Creation of the deallocation
procedure (instance of the
generic subprogram)

   -- Specify first the type and then
the access type.

   V : An_Access := new A_Type;
begin
   Free (V); --V is null after the call

end P;

Dereferencing pointers

  • .all does the access dereference
  • Lets you access the object pointed to by the pointer
  • .all is optional for
  • Access on a component of an array
  • Access on a component of a record

Declaración y definición de tipo access

El acceso a los objetos referenciados por los punteros se hace mediante una derefenciación que puede ser explícita (usando .all), o implícita (cuando se quiere accerder a un componente individual de un objeto compuesto).

-- explicit_dereference ::= name.all
-- implicit_dereference ::= name
type Persona is record 
   Nombre    : String (1 .. 20);
   Apellidos : String (1 .. 50);
   end record;
type Vector is array (1 .. 50) of Integer;

--  Tipos puntero
type Puntero_1 is access Integer;
type Access_Persona is access Persona;
type Access_Vector is access Vector;
   
--  Variables puntero
A, B : Puntero_1;
R    : Access_Persona;
V    : Access_Vector;

--  Derreferenciación explícita
Ada.Integer_Text_IO.Put (P.all);
Ada.Integer_Text_IO.Put (V.all (I)); --  Supuesto I entre 1 y 10
Ada.Text_IO.Put (R.all.Nombre);

--  Derreferenciación implícita
Ada.Integer_Text_IO.Put (V (I));     --  Supuesto I entre 1 y 10
Ada.Text_IO.Put (R.Nombre);
⚠️ **GitHub.com Fallback** ⚠️