Восстановление ошибок конструктора
Borland Pascal позволяет вам с помощью переменной HeapError модуля System (см. Главу 21) установить функцию обработки ошибки динамически распределяемой области. Эта функциональная возмож- ность влияет на способ работы конструкторов объектного типа.
По умолчанию, когда для динамического экземпляра объекта не хватает памяти, вызов конструктора, использующий расширенный син- таксис стандартной процедуры New, генерирует ошибку этапа выпол- нения 203. Если вы установили функцию обработки ошибки динамичес- ки распределяемой области, которая вместо стандартного результата функции 0 возвращает 1, когда выполнить запрос невозможно, вызов конструктора через New возвращает nil (вместо прерывания програм- мы).
Код, выполняющий распределение памяти и инициализацию поля таблицы виртуальных методов (VMT) динамического экземпляра объек- та является частью последовательности вызова конструктора. Когда управление передается на оператор begin операторной части конс- труктора, память для экземпляра уже выделена, и он инициализиро- ван. Если выделения памяти завершается неудачно, и если функция обработки ошибки динамически распределяемой области памяти возв- ращает 1, конструктор пропускает выполнение операторной части и возвращает значение nil. Таким образом, указатель, заданный в вы- полняемом конструктором вызове New, устанавливается в nil.
Когда управление передается на оператор begin операторной части конструктора, для экземпляра объектного типа обеспечивается успешное выполнение памяти и инициализация. Сам конструктор может попытаться распределить динамические переменные для инициализации полей-указателей в экземпляре, однако, такое распределение может завершиться неудачно. Если это происходит, правильно построенный конструктор должен отменять все успешные распределения и, нако- нец, освобождать выделенную для экземпляра объекта память, так что результатом может стать указатель nil. Для выполнения такой "отмены" Borland Pascal реализует стандартную процедуру Fail, ко- торая не требует параметров и может вызываться только из конс- труктора. Вызов Fail приводит к тому, что конструктор будет осво- бождать выделенную для динамического экземпляра память, которая была выделена перед входом в конструктор, и для указания неудачи возвращает указатель nil.
Когда память для динамических экземпляров выделяется с по- мощью расширенного синтаксиса New, результирующее значение nil в заданном указателе-переменной указывает, что операция заверши- лась неудачно. К сожалению, не существует такого указателя-пере- менной, которую можно проверить после построения статического эк- земпляра или при вызове наследуемого конструктора. Вместо этого Borland Pascal позволяет использовать конструктор в виде булевс- кой функции в выражении: возвращаемое значение True указывает на успешное выполнение, а значение False - не неуспешное выполнение из-за вызова в конструкторе Fail.
На диске вы можете найти две программы - NORECVER.PAS и RECOVER.PAS. Оба программы реализуют два простых объектных типа, содержащих указатели. Первая программа не содержит восстановления ошибок конструктора.
Программа RECOVER.PAS демонстрирует, как можно переписать исходный код для реализации восстановления ошибки. Заметим, что для отмены успешного выделения памяти перед вызовом Fail для ито- гового неуспешного выполнения используются соответствующие дест- рукторы в Base.Init и Derived.Init. Заметим также, что в Derived.Init вызов Base.Init содержится внутри выражения, так что можно проверить успешность выполнения наследуемого конструктора.