Что предпочтительнее: Free или FreeAndNil?

41

В чем основное отличие Free и FreeAndNil?

Is FreeAndNil = Free + Nil?

Когда я должен использовать Free и когда я должен использовать FreeAndNil?

Я не получаю их, когда кто-то может мне помочь.

Спасибо заранее.

  • 1
    Расширенное обсуждение здесь: forums.embarcadero.com/thread.jspa?threadID=33112
  • 0
    @Sertac тема, как и многие другие, исчезла
Показать ещё 3 комментария
Теги:

5 ответов

39
Лучший ответ

См

И посмотрите на реализацию:

procedure FreeAndNil(var Obj);
var
  Temp: TObject;
begin
  Temp := TObject(Obj);
  Pointer(Obj) := nil;
  Temp.Free;
end;

Примеры

Рассмотрим следующий код:

procedure TForm1.FormCreate(Sender: TObject);
var
  bm: TBitmap;
begin
  bm := TBitmap.Create;
  bm.LoadFromFile('C:\Users\Andreas Rejbrand\Documents\RAD Studio\6.0\Demos\DelphiWin32\VCLWin32\Football\up.bmp');
  bm.Free;

  if Assigned(bm) then
    bm.SaveToFile('C:\Users\Andreas Rejbrand\Desktop\test.bmp')
  else
    ShowMessage('Cannot save! The bitmap does no longer exist!');
end;

Это создаст ошибку или недопустимое (пустое) растровое изображение на моем рабочем столе, потому что я пытаюсь использовать освобожденный объект. Да, даже если bm был освобожден, он по-прежнему "назначен", т.е. bm все еще указывает на адрес памяти, хотя там нет ничего (полезного). Чтобы преодолеть это, можно установить bm := nil, как гарантию, Затем assigned(bm) вернет false, как хотелось бы. Более или менее, FreeAndNil(bm) является сокращением для bm.Free; bm := nil. Первый оператор освобождает всю память (и ресурсы ОС, время процессора и т.д., Используемые объектом), и bm := nil устанавливает "указатель" bm на nil, так что bm больше не указывает на место, где объект был, но больше не существует. Таким образом, вы (и подпрограммы вроде assigned) не обманетесь, чтобы поверить, что все еще есть объект растрового изображения.

Обсуждение

Некоторые говорят, что вы всегда должны использовать FreeAndNil(foo), а не foo.Free. А почему бы не? Дополнительная инструкция foo := nil, вероятно, не займет слишком много наносекунд для выполнения, и действительно assigned(foo) = false является очень приятным свойством освобожденного объекта. Но опять же, если вы знаете, что делаете, и знаете, что вы никогда не будете использовать объект foo снова, освободив его, тогда вы можете придерживаться только foo.Free. Действительно, некоторые утверждают, что во многих случаях (но не для всех) попытка использовать переменную освобожденного объекта является ошибкой сама по себе. (Конечно, есть случаи, когда вы делаете это намеренно - у вас есть объект foo, который иногда назначается, а иногда и нет.)

  • 4
    «некоторые утверждают, что во многих случаях (но не во всех) попытка использовать освобожденный объект сама по себе является ошибкой» - это всегда ошибка, а не «иногда». Переменные и объекты - это разные звери: переменным иногда может присваиваться «ноль», но это не ноль, а просто неназначенная переменная.
  • 0
    @Cosmin Prund: Конечно. Я изменю это.
Показать ещё 8 комментариев
16

В принципе, FreeAndNil устанавливает ссылку на nil, а затем освобождает объект. Это означает, что он не назначен. Поэтому единственной причиной, по которой вам понадобится использовать FreeAndNil, является то, что ваш код будет повторно использовать ссылку. Если вы находитесь в деструкторе или блоке finally, освобождая объекты, которые вы никогда не будете трогать, просто используйте Free.

См. Delphi Memory Management Made Simple для примера, когда я нашел это полезным. Комментарий Mghie внизу также стоит прочитать.

  • 4
    Фактически, он помещает ссылку в локальную переменную, обнуляет ссылку и затем освобождает объект, используя локальную переменную. FreeAndNil должен был называться NilAndFree ... :)
  • 0
    Ага. Неполные деструкторы и FreeAndNIL () не являются хорошими соратниками.
Показать ещё 1 комментарий
8

Я отвечу по-другому.

Возможно, заполнение вашей ссылки на объект с помощью nil после освобождения объекта не всегда является хорошей идеей.

Таким образом, вы не имеете различия между ссылкой, которая никогда не использовалась (и, следовательно, это nil), и ссылкой, которая была использована, но не должна использоваться в будущем.

Итак, заполняя его магическим числом (подобно тому, что диспетчер памяти FastMM может делать с содержимым блоков памяти, когда эти блоки освобождаются).

- Йерун

  • 0
    Я категорически за FreeAndNil, но ваша идея "магического числа" также привлекательна.
6

@Bharat, разница между Free и FreeAndNil заключается в том, что помимо свободной памяти, используемой объектом FreeAndNil, устанавливается ссылка на объект на nil.

вы можете проверить тезисы ссылок для обсуждения использования Free или FreeAndNil

2

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

Подумайте, что произойдет, если вы НЕ используете FreeAndNil, а затем где-то в вашем коде вы получаете доступ к свободному объекту. Если вам повезет, ваша программа выйдет из строя, когда она вернется домой (да, это крушение - "хороший" крушение). Если вам немного не повезло, он потерпит крах на клиентском компьютере. Тогда начинается настоящая боль!

Как уже указывали другие, сам FreeAndNil неплох. Функция FreeAndNil не нарушена/устарела или что-то вроде этого, и это не повредит ваш код. Некоторые утверждают, что использование FreeAndNil может привести или указать недостаток дизайна.

Я использую FreeAndNil EVEN для локальной переменной. Использование его в локальной переменной кажется POINTLESS, так как переменная исчезает, как только вы выходите из процедуры. Однако это хорошая практика, которая будет стоить вам всего лишь нескольких лишних байтов. Подумайте, что позже вы можете добавить больше кода в конце процедуры, ПОСЛЕ того, где вы освободили объект, код, который (очевидно, случайно) попытается получить доступ к освобожденному объекту. Если объектом был NIL, BABUM, мгновенный AV (пример).
Примечание. Некоторые люди могут сказать, что они никогда не обращались к свободному объекту (в основном это означает, что они никогда не ошибаются), поэтому в этом случае им не нужен FreeAndNil. Ну, я не робот. Я ошибаюсь.

Некоторые консервативные люди могут сказать, что этот простой вызов будет растрачивать ресурсы ОЗУ и ЦП. Я никогда не скажу, что сохранение памяти/процессора плохое. Мне нравится доставлять небольшие/быстрые/монолитные приложения тоже! Но я не думаю, что удаление с помощью FreeAndNil будет тратить больше нескольких байтов и циклов процессора (буквально немного). Это не будет иметь особого значения в повседневной жизни, особенно если вы считаете, что один графический ресурс, такой как символ TButton или значок вашей программы, может занимать 50-300 КБ, а ваша программа может иметь десятки из них.

Pros
Мейсон Уилер уже указывает на статью, в которой показан метод "ленивого создания", который использует FreeAndNil, который мы использовали в один день: http://tech.turbu-rpg.com/106/delphi-memory-management-made-simple

Против
Аллен Бауэр показывает здесь пример того, как использовать FreeAndNil в случае CERTAIN (деструктор визуального компонента) и быть действительно плохим: http://blogs.embarcadero.com/abauer/2010/02/16/38916
Аллен утверждает, что FreeAndNil следует заменить лучшими методами. Например, с FastMM. Тем не менее, вот простой фрагмент кода, в котором FastMM терпит неудачу, в то время как FreeAndNil сохраняет день: http://codeverge.com/embarcadero.delphi.rtl/freeandnil-to-use-or-not-to-use/1067733

Поскольку есть оба аргумента pro и против FreeAndNil, вам решать, нравится это или нет.

  • 2
    -1. «Всегда» неправильно. Если в методе есть локальная переменная, использовать FreeAndNil практически не нужно, поскольку переменная доступна только из локальной области видимости. Если вы не видите, что FreeAndNil там вам не нужен, вам нужно провести рефакторинг кода, чтобы уменьшить количество строк в этом методе. Это плохая идея, чтобы когда-либо дать ответ, который говорит «всегда», если вы не можете абсолютно доказать, что нет никаких исключений из этого правила.
  • 0
    Нет, вы никогда не «случайно» обновляете локальное до глобального. Использование глобальных переменных должно быть редкой вещью, которая тщательно обдумывается. Использование FreeAndNil для покрытия возможного неосторожного программирования - просто еще одна форма небрежного программирования. Любой вызов функции имеет некоторые накладные расходы (даже если он незначителен), и, хотя влияние может быть небольшим, это все равно лишние циклы ЦП, распределение памяти и т. Д. Таким образом, мой голос остается в силе.
Показать ещё 3 комментария

Ещё вопросы

Сообщество Overcoder
Наверх
Меню