B.1. Manual deallocation - JulTob/Ada GitHub Wiki

with Ada.Unchecked_Deallocation;
with Ada.Text_IO;
use Ada.Text_IO;

procedure TestAccess is

  type Int_Access is access all Integer;

  int1: Int_access;
  int2: Int_Access;
  int3: Int_Access := new Integer;
  procedure Free
    is new Ada.Unchecked_Deallocation(
      Integer,
      Int_Access);

  alint: aliased Integer := 12;

  begin
    Free (int3);
   
    int1:= new Integer'(7);
    int2:= int1;
    int2.all:= 3;

    New_Line;
    Put(Integer'Image(int1.all));
    Put(Integer'Image(int2.all));
    Put(Integer'Image(alint));

    int2:= alInt'Access;
    int2.all:=5;

    New_Line;
    Put(Integer'Image(int1.all));
    Put(Integer'Image(int2.all));
    Put(Integer'Image(alint));

    alint:= 2;

    New_Line;
    Put(Integer'Image(int1.all));
    Put(Integer'Image(int2.all));
    Put(Integer'Image(alint));

    Free(int1);
  --  Free(int2);  -- No! Points to allocated object


    end TestAccess;

“all” keyword is included. With this, the type Int_Access is understood to be able to take any other integer’s memory (within certain limits). Basically, if you have a variable that was not allocated dynamically, you can grab its address and assign it to this integer access type. Without this keyword, Int_Access can only have dynamically allocated pieces of memory assigned to it (this can be a desired feature if you want the access type to be very limited in scope). It is not recommended that you use “all.” It’s far better to allocate the memory and then copy into it a value. The reason is if you assign the address of a variable that is within the scope of a method, when the scope of the said method is finished, that piece of memory will be deallocated and you will have an access type pointing to an unknown piece of virtual memory. Let’s just say, if your application enters an uncertain state down the road, this could be why.

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

If you make an array aliased, you will only ensure that the entire array will be pointed at, but its individual elements will not be (remember, you cannot do pointer arithmetic in order to iterate over its parts).

The Deallocate procedure is unique in that it gives you the ability to free up memory that you have piled on the heap. This is crucial in order to free up consumed RAM; otherwise, your program (after some time) will simply run out of free memory and crash. In order to create one, the type of the variable is needed as well as the derived access type.

The new operation is what grabs a piece of RAM on the heap and assigns its access to this access type variable.

If you were to do things out of order, a runtime exception would be thrown stating that attempting to manipulate the memory location of an unallocated piece of RAM is not possible.

with Ada.Unchecked_Deallocation;
with Ada.Text_IO;

procedure Access_Type_Example is
  type Int_Access is access all Integer;
  type Flt_Access is access all Float;
  type Str_Access is access all String;
  
  to_int: Int_Access;
  to_flt: Flt_Access;
  to_Str: Str_Access;

  type My_Class is record
     To_Int: Int_Access;
     To_Flt: Flt_Access;
     To_Str: Str_Access;
     end record;

  Type My_Class_Access is access My_Class;
  
  Object: My_Class_Access;
  BackUp: My_Class_Access;

  -- Functions for deallocation.
  procedure Deallocate is New Ada.Unchecked_Deallocation( Container, My_Class_Access);
  procedure Deallocate is new Ada.Unchecked_Deallocation( To_Str, Str_Access);
  procedure Deallocate is new Ada.Unchecked_Deallocation( To_Flt, Flt_Access);
  procedure Deallocate is new Ada.Unchecked_Deallocation( To_Int, Int_Access);

  Test_Int: aliased Integer:= 94;

  begin
    -- Allocate memory to the pointers.
    Object:= New My_Class_Access;
    Object.To_int:= Test_Int'Access;
    Object.To_flt:= New Float'(0.0);
    Object.To_Str:= New String'("Hello World");

    BackUp:= Object;

    -- Print Object
    Put_Line("Object Content");
    Put_Line(" Integer: " & Integer'Image(BackUp.To_Int.all));
    Put_Line(" Float: "  & FLoat'Image(BackUp.To_Flt.all));
    Put_Line(" String: "  & BackUp.To_Str.all);
 
    -- Reset Object properties.
    BackUp.To_Int.all := 42;
    BackUp.To_Flt.all := 3.1415
    BackUp.To_Str.all := "Hello Ada";

    -- Print Object
    Put_Line("Backup Object Content");
    Put_Line(" Integer: " & Integer'Image(BackUp.To_Int.all));
    Put_Line(" Float: "  & FLoat'Image(BackUp.To_Flt.all));
    Put_Line(" String: "  & BackUp.To_Str.all);

    -- Print Object
    Put_Line("Object Content");
    Put_Line(" Integer: " & Integer'Image(BackUp.To_Int.all));
    Put_Line(" Float: "  & FLoat'Image(BackUp.To_Flt.all));
    Put_Line(" String: "  & BackUp.To_Str.all);