Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Delphi: WinAPI и системное программирование > FreeAndNil


Автор: Delphist 9.2.2007, 13:03
Код

var
procedure MyFreeAndNil(var Obj);
begin
 Obj.Free;
 Obj := Nil
end;

Почему FreeAndNil(obj) и MyFreeAndNil(obj) имеют разный результат выполнения. Объясните пожалуйста.

Автор: Rennigth 9.2.2007, 13:11
В каком смысле?

Автор: Delphist 9.2.2007, 13:32
Цитата(Rennigth @  9.2.2007,  14:11 Найти цитируемый пост)
В каком смысле? 

Почему я спрашиваю данный вопрос. В своей проге я использую DBGridEh. В одной из колонок при клике по ячейке появляется раскрывающийся список(LookUp поля). Так вот если я начну закрывать форму с этим гридом при раскрытом списке, то выскакивает ошибка. После трудоемкой трассировки выяснил место ошибки:
Пример из DBGridEh:
Код

destructor TCustomDBGridEh.Destroy;
begin
 FIntMemTable := nil;
 if FStyle <> nil then
   FStyle.RemoveChangeNotification(Self);
 FColCellParamsEh.Free;
 Selection.Clear;
 FColumns.Free; FColumns := nil;
 ...


Делаю так, ошибка исчезает
Код

destructor TCustomDBGridEh.Destroy;
begin
 FIntMemTable := nil;
 if FStyle <> nil then
   FStyle.RemoveChangeNotification(Self);
 FColCellParamsEh.Free;
 Selection.Clear;
 FreeAndNil(FColumns)
 ...
Почему так происходит?

Автор: Rennigth 9.2.2007, 13:50
Цитата(Delphist @  9.2.2007,  13:32 Найти цитируемый пост)
Почему так происходит?

Точно не изза разницы как дестроить FColumns. Лезь в FColimns и смотри в чем проблема, и почему вылетает AV(думаю что AV).

Автор: Delphist 9.2.2007, 14:03
Цитата(Rennigth @  9.2.2007,  14:50 Найти цитируемый пост)
Точно не изза разницы как дестроить FColumns. 

Незнаю, незнаю... только вот AV пропадает.

Автор: Rennigth 9.2.2007, 14:11
Код

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


Разницы не вижу...  smile 

В таких случаях помогает чашка кофе(или чего покрепче), шапка шамана и бубен. smile 

Автор: MetalFan 9.2.2007, 14:12
Delphist, если пропалает AV в одном месте, это еще не значит, что оно не вылезет в другом ;)

Автор: Delphist 9.2.2007, 14:18
Цитата(MetalFan @  9.2.2007,  15:12 Найти цитируемый пост)
Delphist, если пропалает AV в одном месте, это еще не значит, что оно не вылезет в другом ;)

А что ей вылазить то, я структуру кода не менял. FreeAndNil и (Free + :=nil) выполняют по сути одно и тоже только 1-ый более безопасный.

Автор: MetalFan 9.2.2007, 14:54
Цитата(Delphist @  9.2.2007,  14:18 Найти цитируемый пост)
только 1-ый более безопасный

с чего это вдруг?!
оба способы НЕБЕЗОПАСНЫ если их применять неправильно... 
и вообще, программирование это небезопасная штука) так и лезут ошибки всякие! главное - уметь их правильно найти, локализовать и поправить.

з.ы. это я к тому, что замена Free+:=nil на FreeAndNil - это не выход. есть деятели, что пишут так:
Код

try try
//глючный код или вызов глючных функций
except finally end;

как вас такое? ошибки то не вылазят! значит тоже верное решение? а зачем их искать, если можно просто "спрятать" уведомления об их возниконовении?!

Автор: Delphist 9.2.2007, 15:50
Цитата(MetalFan @  9.2.2007,  15:54 Найти цитируемый пост)
как вас такое? ошибки то не вылазят! значит тоже верное решение? а зачем их искать, если можно просто "спрятать" уведомления об их возниконовении?! 

Вылезут. Потому как try execpt end; спасает от ошибок не связанных с памятью. А вот когда вы попытаетесь обраться к методу уже разрушенного объекта, при чем объект будет разрушен но не равен Nil а имеет адрес $0808088. Как вам это?

Автор: MetalFan 9.2.2007, 16:11
невылезут, если AV происходит в пределах try..except.
SEH "спасает"(читай ловит) от любых ошибок. а try except/finally end - это делфевая "обертка" над виндовым SEH.

Автор: aktuba 9.2.2007, 17:54
Может все дело в следующем:

Код

procedure MyFreeAndNil(var Obj);
begin
 Obj.Free;
 Obj := Nil
end


Ты делаешь объекты Free и объекты = nil, после ты пытаешься присвоить "ничему" nil.

Вот реализация FreeAndNil:

Код

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


Попробуй так же...

Автор: MetalFan 10.2.2007, 00:37
Цитата(aktuba @  9.2.2007,  17:54 Найти цитируемый пост)
Ты делаешь объекты Free и объекты = nil, после ты пытаешься присвоить "ничему" nil.

что-то не понял в смысл фразы.
ничего не мешает сделать
  lSomeObj.Free;
  lSomeObj := nil;

и ни к каким ошибкам это в идеале приводить не должно)
з.ы. если конечно же объект раньше не убит. или при умирании ничего за собой не тащит.

Автор: Alexeis 10.2.2007, 00:42
На счет 
Код

procedure MyFreeAndNil(var Obj);
begin
 Obj.Free;
 Obj := Nil
end

Могу сказать одно, Obj, не является уже указателем на на объект, а указателем на указатель на объект.
Если передавать
Код

procedure MyFreeAndNil(Obj : TObject);
begin
 Obj.Free;
 Obj := Nil
end

то указатель на объект передается по значению, при этом объект Obj уничтожиться но исходный указатель не обнулиться, ведь передана не сама переменная указателя, а ее значение.
  Присвоение Obj := Nil; компилятор понимает не как зануление переменной объекта, которая на самом деле является указателем на объект, а зануление указателя на переменную, которая указывает на объект.
Проблемы возникают из-за того что делфи неявно разыменовывает указатели, причем может делать это цепочечно для доступа к полям и методам, так как-будто и нет вообще указателей. 
  Но при работе с такими переменными как с указателями (присвоение адреса это операция над указателем), неявное разименовывание запрещено, так это помешало бы проводить операции с указателями именно как с указателями, а не с их содержимым. Потому явное приведение
Код

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

является единственно верным.  Pointer(Obj) заставляет компилятор понять, то что нам нужна именно переменная объекта, а не указатель на нее и нужна она нам не для доступа к объекту, а для доступа к адресу записанному в ней (мы ведь приводим ее к указателю), запрещая компилятору различные интерепретации данной операции.
  Вообще операции приведения типа в делфи не являются таки простыми как это может показаться на первый взгляд. Приведение типов всегда является умными и может вызывать даже различные функции без нашего ведома. Так и в этом случае. Интерпретация в лоб Pointer(Obj) дала бы тот же результат, что и первый вариант, но в данном случае приведение является скорее сообщением компилятору о том что мы имеем ввиду записывая такую команду, ведь компилятор думает о том, что мы не знаем о создании неявного указателя на переменную объекта при передаче ее в качестве var параметра.
  Жуть да  smile . Мы должны думать о том, что компилятор думает о нас и действовать исходя из того как этого будет ожидать от нас компилятор.

Автор: MetalFan 10.2.2007, 00:52
Alexeis, хорошо объяснил) аж я после 3х банок пива понял  smile 

Автор: Bose 10.2.2007, 19:10
Delphist, не совсем в тему, но....

От загадочных AV в момент уничтожения DBGridEh можно попробовать избавиться путём установки свойства Datasource:=nil, перед уничтожением.

Автор: Romikgy 10.2.2007, 22:19
добавлю и свои пару копеек 
Цитата(Alexeis @  9.2.2007,  23:42 Найти цитируемый пост)
procedure MyFreeAndNil(Obj : TObject);

имхо можно так
Код

procedure MyFreeAndNil(var Obj : TObject);

а здесь
Цитата(Alexeis @  9.2.2007,  23:42 Найти цитируемый пост)
procedure FreeAndNil(var Obj);
var
  Temp: TObject;
begin
  Temp := TObject(Obj);
  Pointer(Obj) := nil;
  Temp.Free;
end;

Код

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

имхо 

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)