Verkettete Listen: Freigabe


Wie einfach unsere angegebene Realisierung des abstrakten Datentyps liste  in Modula 2 auch aussehen mag, so enthält sie doch ein paar ganz böse Fallen, die zu logischen Fehlern geradezu verleiten. Sie hängen damit zusammen, daß unser abstrakter Datentyp eine Menge von Werten,  die Realisierung aber eine Menge von Objekten  darstellt, und dieser Unterschied ist hier wesentlich.

Unser oben eingeführter Typ liste  enthält tatsächlich keine Listenwerte,  wie sie unsere algebraische Spezifikation beschreibt, sondern Verweise  auf solche Werte, weil er ein Pointertyp ist. Deshalb haben sowohl Zuweisung wie Vergleich jetzt andere Auswirkungen als von früher her gewohnt, und wir müssen außerdem jetzt den durch unsere Geflechte belegten Speicher immer explizit freigeben. Dies kann etwa durch folgende rekursive Prozedur geschehen:

PROCEDURE delete(l: liste);
BEGIN IF l <> NIL
      THEN delete(l^.nach);
           DISPOSE(l);
      END;
END delete;
Vorsicht! Nach ihrem Aufruf zeigt der Inhalt von l immer noch  auf die Halde, ist also ein dangling pointer geworden! Man sollte l anschließend besser mit NIL besetzen (das könnte eine Variante von delete  auch direkt tun), wenn man nicht sofort ein neues Geflecht daranhängt. Es ist auch gute Praxis, jede neu deklarierte Variable eines Pointertyps  explizit mit dem Wert NIL vorzubesetzen (in objektorientierten Sprachen geschieht das oft automatisch, in Modula 2 leider nicht).

Für die rekursive Prozedur delete  gibt es auch eine iterative Variante, deren Wirkungsweise interessant ist (man sollte ein Beispiel durchspielen). Hier durchläuft der Wertparameter l als lokale Hilfsvariable  die ganze Liste bis zum Ende, während ein zweiter Zeiger q immer ein Listenelement weit "nachhinkt". Manchmal nennt man das Schleppzeigertechnik.

PROCEDURE delete(l: liste);
VAR q: liste;
BEGIN WHILE l <> NIL
      DO q := l; l := l^.nach;
         DISPOSE(q);
      END;
END delete;

zurück | Inhalt | Index | vor | Vorlesung

Klaus Lagally, 22. Februar 2000, 19:36