Правила работы с ресурсами
Блоки динамически выделяемой памяти, дескрипторы файлов, логические кисточки Windows и т.п. все это входит в понятие ресурсы. Экземпляры классов также являются ресурсами, так как, во-первых, создание экземпляра класса всегда сопряжено с выделением блока памяти и, во-вторых, класс сам может использовать (выделять в конструкторе) блоки памяти, файлы, таймеры и т.п. Приложение создает (выделяет) ресурсы по мере необходимости, использует их и затем освобождает. Правильная работа с ресурсами — ключ к построению надежно работающих оптимизированных программ.
Использование конструкции try finally
Если ресурс выделяется, используется и высвобождается в пределах одного блока, то обязательно использование следующей конструкции:
{ allocating resource }
try
{ using resource }
finally
{ free resource }
end;
Это гарантирует, что ресурс будет освобожден даже если при его использовании возникла исключительная ситуация.
Удаление ресурсов в деструкторе класса
Если ресурс создается в конструкторе класса, то он обязательно должен удаляться в деструкторе. Могут не удаляться непосредственно ресурсы, высвобождение которых возлагается на объект владелец (пример: в библиотеке VCL при создании большинства объектов указывается объект владелец (owner), при удалении которого удаляются также и все связанные с ним ресурсы).
constructor MyControl.Create(AnOwner: TComponent); begin inherited Create(AnOwner); Timer := TTimer.Create(Self); List := TList.Create; end; destructor MyControl.Destroy; begin List.Free; inherited Destroy; end;
Если ресурс выделяется в одном из методов класса (например, в ответ на некоторое событие), используется и удаляется в других методах, то удаление ресурса обязательно должно дублироваться в деструкторе (с обязательной проверкой на действительность дескриптора ресурса).
procedure WMLButtonDown;
begin
...
{ alloc resource }
...
end;
procedure WMMouseMove;
begin
...
{ use resource }
...
end;
procedure WMLButtonUp;
begin
...
{ free resource }
...
end;
destructor Destroy;
begin
...
if Assigned(Resource) then
{ free resource }
...
end;
Ресурсы создаются только по необходимости и удаляются сразу же после окончания их использования. Отсюда следует, что в конструкторе класса создаются только те ресурсы, которые необходимы на протяжении всего времени жизни экземпляра данного класса. Допускается не удалять экземпляры классов, которые необходимы лишь часть времени жизни объекта-владельца и которые могут быть переведены в активное/неактивное состояние (enabled/disabled). Например, таймер можно использовать следующим образом:
constructor MyControl.Create(AnOwner: Tcomponent); begin inherited Create(AnOwner); Timer := TTimer.Create; Timer.Enabled := False; ... end; destructor MyControl.Destroy; begin Timer.Free; ... inherited Destroy; end; procedure MyControl.WMLButtonDown; begin Timer.Enabled := True; ... end; procedure MyControl.WMLButtonUp; begin Timer.Enabled := False; ... end;
Delphi по умолчанию создает все формы проекта при запуске приложения. Такой подход неприменим для крупных программ, время запуска которых становится слишком большим, а требования к ресурсам непомерными. Первоначально должна создаваться только одна, главная форма. Все остальные создаются и выводятся на экран по запросу пользователя и удаляются сразу же после окончания использования.