Нехватка памяти возможна и в случае статических объектов с динамическими полями. Так, при размещении конструктором динамических полей в куче может возникнуть нехватка памяти. Но, поскольку объект статический, нельзя передать сигнальное значение nil в ссылку — ее попросту нет. Вместо этого предлагается использовать имя конструктора как логическую функцию. Если внутри конструктора была вызвана процедура Fail, то в имени конструктора вернется значение False. В остальных случаях будет возвращаться значение True. Подобным способом анализа можно пользоваться и для проверки работы унаследованных конструкторов.
На рис. 13.8 приводится пример объектов (динамических и с динамическими полями) и их инициализация с обработкой возможных ошибок.
| TYPE
| VectorType = Array [ 1..1000 ] of Real; { вектор }
| MatrixType = Array [1..20,1..20 ] of Real; { матрица }
| VectorTypePtr = ^VectorType; { ссылка на вектор }
| MatrixTypePtr = ^MatrixType; { ссылка на матрицу }
| Vector = OBJECT {статический объект с динамическим полем }
| V : VectorTypePtr;
| CONSTRUCTOR Init( FillVect : Real );
| DESTRUCTOR Done; VIRTUAL;
| PROCEDURE Work; VIRTUAL;
| END;
| ComplexPtr = ^Complex; { Динамический объект с }
| Complex = OBJECT(Vector) { динамическими полями данных }
| M : MatrixTypePtr,
| CONSTRUCTOR Init(FillVect, FillMat : Real);
| DESTRUCTOR Done;
| VIRTUAL;
| PROCEDURE Work; VIRTUAL;
| END;
| { Реализация методов объектов }
| CONSTRUCTOR Vector.Init( FillVect : Real );
| VAR i : Word; { параметр цикла заполнения }
| BEGIN
| New( V ); { попытка разместить V в куче }
| if V=nil then begin
{ при неудаче сделать откат }
| Vector.Done; { завершение работы объекта }
| Fail { объявить сбой конструктора }
| end; {if}
| for i:=1 to 1000 do
|{ поле V создано и заполняется }
| V^[i] := FillVect;
| END;
| DESTRUCTOR Vector.Done;
| BEGIN
| if V<>nil then Dispose( V )
|{ освобождение поля V }
| END;
| PROCEDURE Vector.Work; { метод обработки поля V }
| BEGIN
| { Какие-либо действия над вектором V^ }
| END;
- 291 -
| CONSTRUCTOR Convex.Init( FillVect, FillMat : Real );
| VAR i,j : Word; { параметры циклов заполнения}
| BEGIN
| if not Vector.Init(FillVect) {инициализация прародителя }
| then Fail; {при неудаче сделать откат }
| New( M ); { попытка разместить M в куче }
| if M=nil then begin
{ при неудаче сделать откат }
| Complex.Done; { завершение работы объекта }
| Fail { объявить сбой конструктора }
| end; {if}
| for i:=1 to 20 do
| {поле М создано и заполняется }
| for j:=1 to 20 do
| M^[i,j] := FillMat;
| END;
| DESTRUCTOR Complex.Done;
| BEGIN
| if M<>nil then Dispose( M );
|{ освобождение поля M }
| Vector.Done { освобождение поля V }
| END;
| PROCEDURE Complex.Work; { метод обработки поля М }
| BEGIN
| { Какие-либо действия над матрицей M^ }
| END;
| {$F+} { новая функция анализа распределения памяти}
| FUNCTION HeapFunc(Size: Word) : Integer;
| BEGIN
| HeapFunc := 1
| END;
| {$F-}
| VAR
| Vec : Vector; { экземпляр статического объекта}
| ComPtr : ComplexPtr; { ссылка на динамический объект }
| BEGIN
| HeapError := @HeapFunc; { подстановка функции анализа }
| if not Vec.Init( 1.0 ) { инициализация поля Vec.V }
| then Halt( 1 ); { реакция на неудачу операции }
| New(ComPtr, Init(2,3)); { размещение объекта ComPtr^ }