Если я поместил попытку наконец блок после каждого Объекта. Создать?

У меня есть общий вопрос о лучшей практике в Delphi OO. В настоящее время я поместил попытку наконец блоки где угодно, я создаю объект освободить тот объект после использования (для предотвращения утечек памяти). Например:

aObject := TObject.Create;
try
  aOBject.AProcedure();
  ...
finally
  aObject.Free;
end;

вместо:

aObject := TObject.Create;
aObject.AProcedure();
..
aObject.Free;

Вы думаете, что это - хорошая практика или слишком много служебное? И что относительно производительности?

7
задан Rob Kennedy 27 May 2010 в 16:43
поделиться

8 ответов

На мой взгляд, есть только одна причина, по которой за конструкцией объекта не следует следовать ( или "in", как указал Мейсон ) a try / finally блок.

  1. Если время жизни объекта управляется другим объектом.

Это управление может принимать три формы:

  1. Ссылка на объект имеет область за пределами локального блока и освобождается в другом месте - как член поля, освобожденный в деструкторе.
  2. Объект, немедленно добавленный в список, который отвечает за его освобождение позже.
  3. Объект со связанным менеджером времени жизни, например, как вы передаете владельца элементу управления VCL при построении.

С # 1 , , когда ссылка имеет более широкую область действия , ссылка должна быть установлена ​​на ноль немедленно, если она не создается сразу. Таким образом, когда вы проверяете его для справки, вы будете знать, что у вас есть точные показания. Это чаще всего встречается с объектами-членами, которые создаются как часть более крупного класса, а затем очищаются при уничтожении родительского объекта.

С # 2 , , когда объект добавляется в список , вы хотите использовать блок try-except (один из немногих случаев, когда я используйте один) на тот случай, если возникнет исключение после создания объекта и до того, как он будет добавлен в список управления.В идеале первая строка после построения добавляет его в список, или список на самом деле является фабричным классом, который дает вам объект, уже добавленный в список.

С # 3 , , когда у объекта есть другой менеджер времени жизни , вы действительно должны убедиться, что управление им от этого менеджера является правильным. Если вы создаете элемент управления VCL, у вас может возникнуть соблазн передать его форме (или любому другому элементу управления), но на самом деле это создает дополнительные накладные расходы на создание и разрушение. Если возможно, вы должны явно освободить его, это особенно верно, если вы поместите элемент управления один раз, тогда вы знаете, что освободите его в деструкторе вашей формы или когда он закроется. Вы не можете этого сделать только в том случае, если создание элемента управления более динамично.

Так что да, рекомендуется использовать много блоков try / finally . У вас должно быть только несколько блоков try / except , и большинство из них должны перехватывать очень определенные типы исключений и / или повторно вызывать исключение. Если у вас больше try / except , чем try / finally блоков, то вы делаете это неправильно .

15
ответ дан 6 December 2019 в 04:47
поделиться

Определенно лучше всего использовать try-finally.

В случае возникновения исключения этот объект будет освобожден.

Что касается производительности: измерьте перед оптимизацией.

17
ответ дан 6 December 2019 в 04:47
поделиться

Да, это всегда хорошая идея (необходимая), если код, создающий объект, отвечает за его освобождение. Если нет, то try / finally не подходит, но, опять же, тоже .Free в любом случае!

Однако может быть обременительным иметь этот шаблонный код для дополнения вашей «бизнес-логики», и вы можете рассмотреть подход, который дает такую ​​же гарантию освобождения ваших объектов, но который намного чище (и имеет другие преимущества), , например, моя собственная реализация AutoFree () .

С AutoFree () ваш код может быть записан:

aObject := TObject.Create;
AutoFree(@aObject);

aObject.AProcedure();

или, альтернативно, поскольку реализация использует ссылку на ссылку (для включения автоматического NIL'ing, а также Free'ing), вы можете даже предварительно зарегистрируйте свои ссылки, которые вы хотите использовать в AutoFree'd, чтобы такие служебные декларации не входили в вашу бизнес-логику и сохраняли реальное «мясо» вашего кода как можно более чистым (это особенно полезно, когда потенциально несколько объектов необходимо освободить. ):

AutoFree(@aObject1);
AutoFree(@aObject2);

aObject1 := TObject.Create;
aObject1.AProcedure();

// Later on aObject2 is (or may be) also created
 :

В моем исходном сообщении не показано более позднее дополнение к механизму для поддержки регистрации нескольких ссылок в одном вызове AutoFree (), но я уверен, что вы сможете сами выяснить, какие изменения необходимы для поддержки этого, если вы хотите сделать это:

AutoFree([@aObject1, @aObject2]);

aObject1 := TObject.Create;
aObject1.AProcedure();

// Later on aObject2 is (or may be) also created
 :
1
ответ дан 6 December 2019 в 04:47
поделиться

Как сказал Фрэнк, «что касается производительности: измерьте, прежде чем оптимизировать». Повторяя это, чтобы подчеркнуть.

Кроме того, если вы создаете группу объектов в методе, вам не нужно использовать блок try..finally для каждого из них. Это может привести к уродливому беспорядку с отступами. создавать, пробовать, создавать, пробовать, создавать, пробовать, делать что-то, наконец, бесплатно, наконец, бесплатно, наконец, бесплатно. Ух! Вместо этого вы можете установить ссылки на объекты на nil в верхней части метода, затем создать их все, выполнить один блок try и освободить их все в разделе finally.

Это снизит накладные расходы и производительность (хотя вы, вероятно, никогда не заметите разницы), но, что более важно, сделает ваш код более чистым и легким для чтения при сохранении того же уровня безопасности.

13
ответ дан 6 December 2019 в 04:47
поделиться

Чтобы ответить на вторую часть вашего вопроса:
попробуйте, наконец, почти не имеет накладных расходов.

На самом деле существует множество методов с неявным блоком try ... finally. Например, просто имея функцию, использующую локальную переменную любого типа интерфейса и присваивая ей значение.

- Джерун

5
ответ дан 6 December 2019 в 04:47
поделиться

Если вы создаете объект в конструкторе класса и объект будет принадлежать вложенному классу, вы захотите освободить его в деструкторе класса-владельца.

Я обычно использую FreeAndNil() вместо вызова Free.

EDIT: Но, как сказали другие, вы определенно всегда хотите освободить то, что вы создаете.

2
ответ дан 6 December 2019 в 04:47
поделиться

Даже если очень рекомендуется делать это, я не всегда буду это делать.

Мои правила использования или неиспользования try/finally:

  • Шанс того, что объект разрушится и сгорит.
  • Количество раз, когда объект создается. Если я знаю, что ваш объект создается редко (не более 5-6 раз за время жизни приложения), я могу смириться с утечкой памяти в 20 КБ - на случай, если он "умрет", не будучи освобожденным.
  • Объем утечки памяти в случае падения объекта.
  • Сложность кода. Try/except заставляют код выглядеть очень уродливо. Если есть процедура в 5 строк, я всегда использую try/except.
  • Длительность работы приложения. Если ваше приложение должно работать несколько дней, то я определенно хочу освободить ЛЮБОЙ участок памяти, иначе утечка будет накапливаться.

Единственное место, где трудно принять решение - это когда вам нужна производительность при создании объекта тысячи раз (например, в цикле). В этом случае я не использую try/except, если объект выполняет простые задачи и есть небольшой шанс увидеть его крах.

-4
ответ дан 6 December 2019 в 04:47
поделиться

В прошлом году на Delphi Developer days я видел некоторые частные запасы кода Марко Канту, и он вызывает try finally каждый раз, когда что-либо создает.

Кто-то спросил его об этом, и он сказал, что пытается делать это все время.

Но это особенно хорошая идея для многопоточного кода, когда дело доходит до входа и выхода из критических разделов, хотя это не по теме, это полезно помнить.

Очевидно, что иногда это немного навязчиво, и если в вашей рабочей среде не принято быть точным в своей робости, это может сделать вас похожим на пустышку. Но я думаю, это хорошая идея. Это похоже на попытку Delphi принудительно выполнить сборку мусора вручную.

5
ответ дан 6 December 2019 в 04:47
поделиться
Другие вопросы по тегам:

Похожие вопросы: