Сам метод Free
явно не вызывает исключение, но вызывает виртуальный деструктор Destroy
, который, безусловно, может вызвать исключение.
Так что если вы хотите быть уверены, что все ваши объектыуничтожен, даже если один из деструкторов вызовет исключение, в результате вы получите код, подобный следующему:
a := TMyObject.Create;
try
b := TMyObject.Create;
try
...
finally
b.Free;
end;
finally
a.Free;
end;
Сказав это, следует придерживаться принципа разработки, согласно которому вы не должны вызывать исключения в деструкторе.Так что, на мой взгляд, вполне разумно принять точку зрения, что если в деструкторе возникает исключение, то ваша программа в значительной степени скрыта.Утечка предметов в этот момент не является чем-то, о чем можно беспокоиться.Если ваш деструктор вызвал исключение, то вы, вероятно, уже просочились, потому что этот деструктор не запустился до завершения.
Так что, на мой взгляд, вполне разумно сгруппировать некоторые вызовы Free
и, конечно, выизбегайте глубоко вложенных try
/ finally
, к которым стоит стремиться.
Если вам нужен только один try
/ finally
, не забудьте написать код, подобный следующему:
a := nil;
b := nil;
try
a := TMyObject.Create;
b := TMyObject.Create;
...
finally
b.Free;
a.Free;
end;
В моей собственной кодовой базе у меня есть несколько вспомогательных методов, которые делают это чище.Тогда код может выглядеть следующим образом:
InitialiseNil(a, b);
try
a := TMyObject.Create;
b := TMyObject.Create;
...
finally
FreeAndNil(b, a);
end;
Я дал своему FreeAndNil
то же имя, что и функции в SysUtils
, что на первый взгляд может показаться странным, но это безопасно и удобно делатьтак.Естественно, эти помощники приходят в себя, когда у вас есть даже более двух предметов.