2010-07-01 2 views
42

В чем основное отличие между Free и FreeAndNil?Что предпочтительнее: Free или FreeAndNil?

Is FreeAndNil = Free + Nil?

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

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

Заранее благодарен.

+1

Расширенное обсуждение здесь: https://forums.embarcadero.com/thread.jspa?threadID=33112 –

+0

@Sertac поток, как и многие другие, исчез – mjn

+1

Новые обсуждения на нетехнических [здесь] (https: //forums.embarcadero.com/thread.jspa?threadID=65321&tstart=15) и [здесь] (https://forums.embarcadero.com/thread.jspa?threadID=63906&tstart=0) – mjn

ответ

42

См

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

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) вернет ложь, как хотелось бы. Более или менее, 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: Конечно. Я изменю это. –

+0

@Cosmin - не совсем так. Переменные, которые не назначены, вряд ли будут NIL, если они не являются строками или ссылками на интерфейс. С другой стороны, неназначенные члены класса наверняка будут NIL, если вы не намеренно переопределите реализацию NewInstance. – Deltics

6

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

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

17

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

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

+4

На самом деле он помещает ссылку в локальный var, nils ссылается и затем освобождает объект, используя локальный var. FreeAndNil следует назвать NilAndFree ... :) –

+0

Да. Неполные деструкторы и FreeAndNIL() не являются хорошими друзьями. – Deltics

+1

@Marjan, у меня недавно был случай, когда это имя, вероятно, спасло меня некоторое время в определении ошибки в слишком сложной реализации singleton, которая включала в себя доступ к переменным класса из деструктора, который ранее был «FreeAndNil''d ...;) –

8

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

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

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

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

--jeroen

2

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

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

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

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

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

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

Против
Allen Bauer показывает здесь пример о том, как с помощью FreeAndNil в отдельном случае (деструктор визуального компонента) и быть действительно плохим: 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, потому что var доступен только из локальной области. Если вы не можете ** видеть **, что вам не нужен FreeAndNil, вам нужно реорганизовать свой код, чтобы уменьшить количество строк в этом методе. Плохая идея когда-либо давать ответ, который говорит «всегда», если вы не можете абсолютно доказать, что исключений из этого правила нет. –

+0

Нет, вы никогда не «случайно» обновляете локальную до глобальной. Использование глобальных переменных должно быть редкой вещью, которая тщательно рассматривается. Использование FreeAndNil для покрытия возможных небрежных программ - это просто еще одна форма небрежного программирования. Любой вызов функции имеет некоторые накладные расходы (даже если это незначительно), и, хотя влияние может быть небольшим, все еще не нужны циклы процессора, распределение памяти и т. Д. Таким образом, мой голос все еще стоит. –

+0

Если вы не можете сказать, что вы никогда не обновляете локальную локальную сеть *, и ваша работа на полную ставку - это написание кода, вы должны осторожно вернуться с клавиатуры и найти новое задание. Я могу честно сказать, что за последнее десятилетие я * никогда * случайно не обновил локальную переменную до глобальной и имел проблему в методе, который использует эту локальную переменную, где правильным решением будет FreeAndNil. У меня есть несколько производственных приложений на сумму более 5 миллионов строк кода, а grep источника находит два экземпляра FreeAndNil в моем собственном коде. –

Смежные вопросы