В Delphi 5 может ли Free создать исключение? - PullRequest
7 голосов
/ 08 февраля 2012

В Delphi 5 в настоящее время я написал код, который вызывает Free для нескольких переменных в блоке finally, например,

...
finally
    a.Free;
    b.Free;
    c.Free;
end;

В этом коде предполагается, что Free никогда не может быть повышен, поскольку, если, например, a.Free повышен, память для b и c будет вытекать. Оправдано ли это предположение?

Ответы [ 5 ]

11 голосов
/ 08 февраля 2012

Сам метод 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, что на первый взгляд может показаться странным, но это безопасно и удобно делатьтак.Естественно, эти помощники приходят в себя, когда у вас есть даже более двух предметов.

3 голосов
/ 08 февраля 2012

Зависит от того, что происходит в деструкторе.

2 голосов
/ 09 февраля 2012

Может быть 2 вещи, которые могут вызвать SomeObj.Free для создания исключения:

  1. Необработанное исключение в деструкторе экземпляра SomeObj класса или одного из его предков.
  2. Неверная ссылка на класс из-за неинициализированной переменной SomeObj.

В вашем случае, если a.Free вызовет исключение по любой из вышеперечисленных причин, произойдет утечка памяти для объекта bи c и, возможно, какая-то утечка внутри объекта a из-за необработанного исключения в деструкторе.

1 голос
/ 08 февраля 2012

если ваш a.free вызовет исключение, a (в зависимости от того, сколько деструктор освободил от полей объекта a), b и c объекты будут утечками, потому что выполнение будет прервано. В любом случае, в вашем деструкторе что-то не так, если возникает ошибка. таким образом, вы должны защищать код с помощью блоков try..finally, но ИМХО вы должны убедиться, что деструкторы не дают вам ошибок ни при каких обстоятельствах.

0 голосов
/ 08 февраля 2012

Конечно, FREE может выдавать исключения - так что да, вы потеряете память в своем коде, если A.FREE выдаст исключение, B.FREE и C.FREE не будут вызваны.

Вопрос в том, хотите ли вы обработать исключения или позволить им случиться? Это будет зависеть от того, для чего предназначен ваш код, будут ли другие разработчики использовать его (например). Чтобы предотвратить утечку памяти, вы должны вложить разделы try..finally;

a:=tobject.create;
try
  b:=tobject.create;
  try
    c:=tobject.create;

    ...

  finally
    c.free;
  end;
finally
  b.free;
end;
a.free;

Вроде вещи. Вопрос в том, что на самом деле делает ваш код, если вы также должны обернуть A.FREE в раздел try..finally, хотя, наверное, вам следует.

...