Пример динамического выделения и высвобождения памяти для однонаправленного списка объектов.

Создадим список, в котором хранятся различные фигуры — объекты иерархии с классом-прародителем tDot. Введем запись типа "узел", ссылающийся на одну фигуру и один другой (предыдущий) узел:

Тело списка (или для простоты просто список) будет состоять из набора таких узлов. Самый первый узел, которому не на кого указывать как на предыдущий, имеет указатель со значением nil. Указатель на последний узел списка хранится в поле LastNode нашего объекта. Этот объект типа tList реально будет являться заголовком списка, где хранятся нужные поля данных (в нашем случае — pLastNode) и ссылки на методы объекта. Сам же список будет создаваться в динамической области памяти. К списку можно добавлять новый узел методом Add, а уничтожать методом Done. Метод Report позволяет в процессе работы выводить информацию о координатах фигур, находящихся в списке.

unit ListDemo;

uses…,Figures,FigArc;

type

tpFigure=tpDot;

tpNode=^tNode;{для указателей разрешен опережающий вызов описания типа}

tNode= {хотя тип tNode определен только в этом месте}

record {каждый узел списка состоит из:}

pFigure:tpFigure; {-указателя на фигуру}

pPrevious:tpNode; {-указателя на предыдущий узел списка}

end;

tList=

object {объект этого типа будет управлять списком}

pLastNode:tpNode; {указатель на последний узел списка}

constructor Init; {инициализация полей и методов "управляющего"

объекта}

destructor Done;virtual;{уничтожение списка и высвобождение памяти}

procedure Add(pFig:tpFigure); {добавить узел со ссылкой на

pFig в конец списка}

procedure Report; {вывод на экран информации о списке}

end;

{-реализация методов tList-}

constructor tList.Init;

begin

pLastNode:=nil; {в списке узлов нет, и pLastNode никуда не указывает}

end;

procedure tList.Add(pFig:tpFigure); {в качестве параметра передается

указатель на фигуру, которую надо внести в список}

var pCurrent:tpNode; {локальная переменная типа 'указатель на узел'}

begin

New(pCurrent); {создали новый узел, он пока не в списке}

pCurrent^.pFigure:=pFig; {установили его указатель pFigure на фигуру,

на которую "настроен" pFig}

pCurrent^.pPrevious:=pLastNode; {установили его указатель pPrevious

на последний узел списка; если это первый узел списка,

то pPrevious получает значение nil - см. конструктор}

pLastNode:=pCurrent; {обозначили узел как последний в списке;

теперь наш узел состоит в списке}

end;

destructor tList.Done;

var pCurrent:tpNode;

begin

while pLastNode<>nil do {движемся от последнего узла списка до начала,

т.е. пока pLastNode не укажет на nil}

begin

pCurrent:=pLastNode; {настраиваем pCurrent на последний узел}

Dispose(pCurrent^.pFigure,Done);{высвобождаем память, занятую под

фигуру. Важно, что ее метод Done - виртуальный}

pLastNode:= pCurrent^.pPrevious; {обозначаем предыдущий узел как

последний}

Dispose(pCurrent); {устраняем узел, на который настроен указатель

pCurrent}

end;

end;

procedure tList.Report; {вывод на экран координат фигур списка}

var pCurrent:tpNode;

tmp:string;

begin

pCurrent:=pLastNode; {настроились на последний узел списка}

while pCurrent<>nil do {движемся по списку до первого узла}

begin

Str(pCurrent^.pFigure^.GetX:3,tmp); {в строку tmp вводим 3 цифры

значения X}

OutText('X='+tmp+' '); {выводим значение X на экран}

Str(pCurrent^.pFigure^.GetY:3,tmp); {в строку tmp – значениеY}

OutText('Y='+tmp+' '); {выводим значение Y на экран}

pCurrent:=pCurrent^.pPrevious; {настроились на предыдущий узел}

end;

end;

{-переменные основной программы-}

var

aList:tList; {экземпляр типа "список"}

pArc:tpArc; {указатель на дугу}

pCircle:tpCircle; {указатель на окружность}

{-основная программа-}

begin

InitGraph(GraphDriver,GraphMode,''); {инициализация графики}

if GraphResult<>GrOk then Halt(1); {в случае ошибки - остановка

программы}

aList.Init; {создали список. В нем нет узлов, а поле pLastNode равно nil}

aList.Add(New(tpArc,Init(120,80,20,10,90))); {добавили в список

дугу}

aList.Add(New(tpCircle,Init(300,200,100))); {добавили окружность}

aList.Add(New(tpCircle,Init(150,150,50))); {другую окружность}

aList.pLastNode^.pFigure^.Show; {показали последнюю фигуру списка}

aList.pLastNode^.pFigure^.MoveTo(200,200); {передвинули ее}

aList.Report; {вывели на экран координаты фигур списка}

aList.Add(New(tpDot,Init(100,100))); {добавили в список точку}

aList.pLastNode^.pPrevious^.pPrevious^.pFigure^.Show; {показали

третью с конца фигуру, т.е. первую окружность}

aList.pLastNode^.pFigure^.Move(20,50); {передвинули точку}

aList.Report; {вывели координаты фигур списка}

aList.Done; {уничтожили список}

OutTextXY('Press <Enter> to exit',0,10);

end.