TP-programmation-imperative/tp08/exemples_memoire_dynamique.adb

126 lines
3.6 KiB
Ada
Raw Normal View History

2023-06-10 19:03:54 +00:00
with Piles;
with Ada.Text_IO; use Ada.Text_IO;
with Ada.Unchecked_Deallocation; --! Pour libérer la mémoire allouée dynamiquement
procedure Exemples_Memoire_Dynamique is
type T_Pointeur_Integer is access Integer;
procedure Free
is new Ada.Unchecked_Deallocation (Integer, T_Pointeur_Integer);
-- ou Ada.Unchecked_Deallocation (Object => Integer, Name => T_Pointeur_Integer);
-- Allocation dynamique de mémoire et libération de cette mémoire.
procedure Illustrer_Memoire_Dynamique is
Ptr1 : T_Pointeur_Integer;
begin
Ptr1 := new Integer; -- Allocation dyamique de mémoire
Ptr1.all := 5; -- Utilisation de cette mémoire
Put_Line ("Ptr1.all = " & Integer'Image (Ptr1.all));
Free (Ptr1); -- Libération de la mémoire
pragma Assert (Ptr1 = Null); -- Free met le pointeur à Null
end Illustrer_Memoire_Dynamique;
-- Mémoire allouée dynamiquement et non libérée.
procedure Illustrer_Memoire_Dynamique_Sans_Free is
Ptr1 : T_Pointeur_Integer;
begin
Ptr1 := new Integer;
Ptr1.all := 5;
Put_Line ("Ptr1.all = " & Integer'Image (Ptr1.all));
Free (Ptr1); -- on libère la mémoire
end Illustrer_Memoire_Dynamique_Sans_Free;
-- Illustrer la libération explicite de la mémoire et les précautions à
-- prendre...
procedure Illustrer_Memoire_Dynamique_Erreur is
Ptr1, Ptr2 : T_Pointeur_Integer;
begin
Ptr1 := new Integer;
Ptr2 := Ptr1;
Ptr1.all := 5;
pragma Assert (Ptr1.all = 5);
pragma Assert (Ptr2.all = 5);
Free (Ptr1);
pragma Assert (Ptr1 = Null); -- le pointeur est bien mis à Null
pragma Assert (Ptr2 /= Null);
-- XXX Quelle est la valeur de Ptr2.all ? 0
-- Put_Line ("Ptr2.all = " & Integer'Image (Ptr2.all));
-- -> opération invalide
-- Ptr2.all := 7;
-- pragma Assert (Ptr2.all = 7);
-- -> opérations invalides
-- XXX A-t-on le droit de manipuler Ptr2.all ? oui
-- XXX Que se passe-t-il si on exécute le programme avec valkyrie ?
-- -> il nous dit que l'on utilise une zone mémoire que l'on a libéré !
--
-- Le terme "Unchecked" dans Unchecked_Deallocation vient de là. Ada
-- n'a pas de moyen de contrôler que quand on libère de la mémoire il
-- n'y a plus aucun pointeur dans le programme qui la référence. C'est
-- à la charge du programmeur ! Utiliser un ramasse-miettes (garbage
-- collector) résoud ce problème car il ne libèrera la mémoire que s'il
-- n'y a plus aucune référence dessus.
end Illustrer_Memoire_Dynamique_Erreur;
-- Illustrer les conséquence d'avoir un paramètre en in qui est un pointeur.
procedure Illustrer_Pointeur_In is
procedure SP (Ptr : in T_Pointeur_Integer) is
begin
Ptr.all := 123;
end SP;
Ptr : T_Pointeur_Integer;
begin
Ptr := new Integer;
Ptr.all := 111;
SP (Ptr);
-- XXX Quelle est la valeur de Ptr.all ? 123
Put_Line ("valeur de Ptr.all ? " & Integer'Image (Ptr.all));
Free (Ptr);
end Illustrer_Pointeur_In;
-- Illustrer la question "Faut-il Detruire un pile chaînée si c'est
-- une variable locale d'un sous-programme ?".
procedure Illustrer_Pile_Locale is
package Pile is
new Piles (Integer);
use Pile;
P : T_Pile;
begin
Initialiser (P);
Empiler (P, 4);
Put_Line ("Sommet = " & Integer'Image (Sommet (P)));
Empiler (P, 2);
Put_Line ("Sommet = " & Integer'Image (Sommet (P)));
-- XXX P étant une variable locale du sous-programme, a-t-on besoin
-- d'appeler Detruire dessus ? non
end Illustrer_Pile_Locale;
begin
Illustrer_Memoire_Dynamique;
Illustrer_Memoire_Dynamique_Sans_Free;
Illustrer_Memoire_Dynamique_Erreur;
-- Illustrer_Pointeur_In
-- Illustrer_Pile_Locale;
end Exemples_Memoire_Dynamique;