Форум: "Прочее";
Текущий архив: 2013.03.22;
Скачать: [xml.tar.bz2];
ВнизПочему FreeAndNil такой, какой он есть? Найти похожие ветки
← →
Омлет © (2012-06-19 11:12) [0]Почему ссылка на объект обниляется перед вызовом деструктора, а не после?
procedure FreeAndNil(var Obj);
var
Temp: TObject;
begin
Temp := TObject(Obj);
Pointer(Obj) := nil;
Temp.Free;
end;
Наступил на грабли.. В деструкторе объекта генерируется событие, в обработчике которого было обращение к этому объекту (не через Sender). А, поскольку ссылка на него уже стерта (FreeAndNil постарался), получаем AV.
← →
Ega23 © (2012-06-19 11:16) [1]
> Наступил на грабли.. В деструкторе объекта генерируется
> событие, в обработчике которого было обращение к этому объектуTObject = class
public
.....
procedure AfterConstruction; virtual;
procedure BeforeDestruction; virtual;
?
← →
Плохиш © (2012-06-19 11:23) [2]
> В деструкторе объекта генерируется событие, в обработчике
> которого было обращение к этому объекту (не через Sender).
>
Класс не должен знать ничего о каких-то ссылках на свои экземпляры.
← →
Омлет © (2012-06-19 11:26) [3]> Ega23 © (19.06.12 11:16) [1]
В данном случае BeforeDestruction ничем не поможет.
← →
Ega23 © (2012-06-19 11:35) [4]
unit Unit44;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
type
TMyClass = class (TObject)
private
FOnNotify: TNotifyEvent;
published
public
destructor Destroy; override;
procedure Foo;
property OnNotify: TNotifyEvent read FOnNotify write FOnNotify;
end;
TForm44 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
procedure Bar(Sender: TObject);
public
{ Public declarations }
end;
var
Form44: TForm44;
implementation
{$R *.dfm}
{ TForm44 }
procedure TForm44.Bar(Sender: TObject);
begin
if Sender is TMyClass then
TMyClass(Sender).Foo;
end;
procedure TForm44.Button1Click(Sender: TObject);
var
obj: TMyClass;
begin
obj := TMyClass.Create;
try
obj.OnNotify := Bar;
finally
FreeAndNil(obj);
end;
end;
{ TMyClass }
destructor TMyClass.Destroy;
begin
if Assigned(FOnNotify) then
FOnNotify(Self);
inherited;
end;
procedure TMyClass.Foo;
begin
ShowMessage("Foo");
end;
end.
← →
Омлет © (2012-06-19 11:39) [5]> Плохиш © (19.06.12 11:23) [2]
> Класс не должен знать ничего о каких-то ссылках на свои экземпляры.
Он и не знает. Код довольно безобидный:
// Обработчик события OnChangeConnectionEvent для fDBConnector
procedure TForm1.ChangeConnectionEvent(Sender: TObject);
begin
if fDBConnector.ConnectionState = csDisconnected then // Тут AV, т.к. fDBConnector уже = nil
AddToLog("Disconnected.");
end;
procedure TForm1.FormDestroy(Sender: TObject);
begin
FreeAndNil(fConnector); // Получаем Free->Disconnect->ChangeConnectionEvent->AV
end;
Если напишемif TDBConnector(Sender).ConnectionState ...
проблема решится.
Но вопрос не в этом.
← →
Омлет © (2012-06-19 11:44) [6]> Ega23 © (19.06.12 11:35) [4]
Я знаю, как решить проблему (см. [5]). Вопрос озвучен в заголовке ветки.
← →
Sha © (2012-06-19 11:56) [7]Для большей распущенности?
Чтобы вложенный вызов Free через ту же переменную был безопасен?
← →
Омлет © (2012-06-19 12:03) [8]Должен быть какой-то веский смысл заводить доп. переменную вместо того, чтобы просто написать:
procedure FreeAndNil(var Obj);
begin
Obj.Free;
Obj := nil;
end;
← →
CRLF (2012-06-19 12:07) [9]
> Омлет © (19.06.12 12:03) [8]
Если Obj.Free по какой-то причине упадёт, то... продолжи мысль :-)
← →
Омлет © (2012-06-19 12:07) [10]> Sha © (19.06.12 11:56) [7]
> Чтобы вложенный вызов Free через ту же переменную был безопасен?
Как это?
← →
Омлет © (2012-06-19 12:09) [11]> CRLF (19.06.12 12:07) [9]
> Если Obj.Free по какой-то причине упадёт, то... продолжи мысль :-)
Точно! Думаю, ты прав.
← →
Дмитрий С © (2012-06-19 12:34) [12]
> procedure TForm1.FormDestroy(Sender: TObject);
> begin
> FreeAndNil(fConnector); // Получаем Free->Disconnect->ChangeConnectionEvent-
> >AV
> end;
А почему нельзя просто fConnector.free ?
← →
Дмитрий С © (2012-06-19 12:35) [13]
> // Обработчик события OnChangeConnectionEvent для fDBConnector
> procedure TForm1.ChangeConnectionEvent(Sender: TObject);
>
> begin
> if fDBConnector.ConnectionState = csDisconnected then //
> Тут AV, т.к. fDBConnector уже = nil
> AddToLog("Disconnected.");
> end;procedure TForm1.ChangeConnectionEvent(Sender: TObject);
var fDBConnector:TDBConnector absolute Sender;
begin
if fDBConnector.ConnectionState = csDisconnected then // Тут AV, т.к. fDBConnector уже = nil
AddToLog("Disconnected.");
end;
← →
Anatoly Podgoretsky © (2012-06-19 12:51) [14]
> Омлет © (19.06.12 11:12)
Какая тебе разница до или после, все равно ссылка уже разрушена.
Да и код у тебя не безобидный, попытка работать после разрушения.
← →
Омлет © (2012-06-19 12:52) [15]> Дмитрий С
Да не спрашивал я, как избежать AV.
Ты уже четвертый, кто вопрос не читал.
← →
Омлет © (2012-06-19 12:53) [16]
> Anatoly Podgoretsky © (19.06.12 12:51) [14]
Пятый.
← →
Sha © (2012-06-19 13:01) [17]
> Омлет © (19.06.12 12:07) [10]
> > Sha © (19.06.12 11:56) [7]> Чтобы вложенный вызов Free
> через ту же переменную был безопасен?Как это?
Ну, если ты перекрыл Free, то теоретически есть шанс вызвать его еще раз из него же.
← →
Омлет © (2012-06-19 13:11) [18]> Sha © (19.06.12 13:01) [17]
> Ну, если ты перекрыл Free, то теоретически
> есть шанс вызвать его еще раз из него же.
Почему повторный вызов будет безопасен? Ведь AV же случится.
← →
Давайте будем жрать! (2012-06-19 13:13) [19]Смотря как перекроешь.
← →
Sha © (2012-06-19 13:14) [20]Не случится.
Посмотри, что будет, при такой последовательности вызовов:
FreeAndNil->Free->Disconnect->FreeAndNil
← →
Давайте будем жрать! (2012-06-19 13:16) [21]
> Посмотри, что будет, при такой последовательности вызовов:
> FreeAndNil->Free->Disconnect->FreeAndNil
Есть мнение, что ничего хорошего. Фри — невиртуальный. ФриЭндНил вызовет ТОбжект.Фри, перекрытие пропадёт втуне.
← →
Дмитрий С © (2012-06-19 13:24) [22]Простите.
> Почему ссылка на объект обниляется перед вызовом деструктора,
> а не после?
Потому что такая функция. Как раз вопрос в том, почему ты ее решил применить, и теперь жалуешься, что она тебе не подходит?
Кстати TObject(nil).Free() - не вызывает AV
← →
Sha © (2012-06-19 13:28) [23]
> Давайте будем жрать! (19.06.12 13:16) [21]
> > Посмотри, что будет, при такой последовательности вызовов:
> > FreeAndNil->Free->Disconnect->FreeAndNilЕсть мнение, что
> ничего хорошего. Фри — невиртуальный. ФриЭндНил вызовет
> ТОбжект.Фри, перекрытие пропадёт втуне.
Зато Destroy виртуальный.
← →
Омлет © (2012-06-19 13:30) [24]> Sha © (19.06.12 13:14) [20]
Теперь понял.
> Дмитрий С © (19.06.12 13:24) [22]
> Как раз вопрос в том, почему ты ее решил применить, и теперь
> жалуешься, что она тебе не подходит?
Мне всё подходит. Просто раньше не обращал внимания на реализацию этой процедуры - из её названия думал, что сначала Free, а потом Nil. Оказалось наоборот.
← →
Давайте будем жрать! (2012-06-19 13:31) [25]
> Sha © (19.06.12 13:28) [23]
Тогда к чему [17]?
← →
Sha © (2012-06-19 13:33) [26]
> Давайте будем жрать! (19.06.12 13:31) [25]
> > Sha © (19.06.12 13:28) [23]Тогда к чему [17]?
Виноват, был не совсем точен.
← →
oxffff © (2012-06-19 14:22) [27]
> Омлет © (19.06.12 11:12)
> Почему ссылка на объект обниляется перед вызовом деструктора,
> а не после?
>
> procedure FreeAndNil(var Obj);
> var
> Temp: TObject;
> begin
> Temp := TObject(Obj);
> Pointer(Obj) := nil;
> Temp.Free;
> end;
Чтобы выявить цикл при разрушении. Поэтому стоит var.
← →
oxffff © (2012-06-19 14:24) [28]
> Чтобы выявить цикл при разрушении.
В смысле не цикл разрушения. А цикл связности.
← →
Anatoly Podgoretsky © (2012-06-19 14:37) [29]> oxffff (19.06.2012 14:22:27) [27]
var что бы можно было вненею ссылку изменить.
← →
robt (2012-06-19 14:44) [30]
> Почему ссылка на объект обниляется перед вызовом деструктора,
> а не после?
потомучто деструктор может выполняться оч долго и есть такая фигня, как многозадачность
← →
oxffff © (2012-06-19 15:02) [31]
> есть такая фигня, как многозадачность
Я плакалъ.
← →
oxffff © (2012-06-19 15:03) [32]
> Anatoly Podgoretsky © (19.06.12 14:37) [29]
> > oxffff (19.06.2012 14:22:27) [27]
>
> var что бы можно было вненею ссылку изменить.
Не, чтобы кофе налить.
← →
Cobalt © (2012-06-19 16:25) [33]Если объект может быть обнулен, то
if Assigned(obj)
спасет отца русской демократии
← →
DVM © (2012-06-19 16:38) [34]Вот если кому интересно, тут про FreeAndNil кое-какие мысли:
http://www.gunsmoker.ru/2009/04/freeandnil-free.html
← →
brother © (2012-06-19 16:46) [35]перечитал, теперь поведение
> Почему ссылка на объект обниляется перед вызовом деструктора,
> а не после?
становится более понятным, впрочем, лично Я стараюсь придерживаться именно FreeAndNil...
← →
Омлет © (2012-06-19 16:58) [36]> DVM © (19.06.12 16:38) [34]
> http://www.gunsmoker.ru/2009/04/freeandnil-free.html
Спасибо. Т.е., с точки зрения GunSmoker-а объект обниляется перед Free, чтобы было легче вылавливать ошибки )
Это уже третий вариант ответа на мой вопрос.
← →
Sha © (2012-06-19 17:05) [37]Это только одна сторона медали. Одни ошибки вылавливаем, другие прячем.
Обе крайности вредны, хотя мне ближе другая )
Самому контролировать поведение своей программы как-то спокойнее.
← →
brother © (2012-06-19 17:13) [38]> Самому контролировать поведение своей программы как-то спокойнее.
а если код сложный?
← →
brother © (2012-06-19 17:13) [39]+ копи паст?
← →
Sha © (2012-06-19 17:39) [40]> а если код сложный?
> + копи паст?
ошибки надо исправлять, а не прятать
← →
brother © (2012-06-19 18:56) [41]> ошибки надо исправлять
вот FreeAndNil и поможет...
← →
Sha © (2012-06-19 19:07) [42]> вот FreeAndNil и поможет...
[37]
← →
Владислав © (2012-06-19 23:21) [43]Почему, если выстрелить себе в ногу, будет больно?..
> Наступил на грабли..
Вот чтобы было больно сразу после выстрела, а не через какое-то время, после прилетания черенка по голове.
Я к чему, помогло таки?
← →
Омлет © (2012-06-19 23:55) [44]> помогло таки?
Помогло.
← →
Sha © (2012-06-20 00:31) [45]попытки "обнулить переменную совсем" также "помогают" потерять контроль над программой
← →
oxffff © (2012-06-20 00:34) [46]
> Sha © (20.06.12 00:31) [45]
> попытки "обнулить переменную совсем" также "помогают" потерять
> контроль над программой
Это как?
← →
Sha © (2012-06-20 00:35) [47]что как?
← →
oxffff © (2012-06-20 00:38) [48]Пример нужно.
← →
Sha © (2012-06-20 00:45) [49]Примера, как "обнулить переменную совсем", у меня нет. Была тут давно-давно веселая ветка, в которой ТС настойчиво хотел это сделать так, чтобы переменной не осталось вовсе, наверно. Думаю, многим она запомнилась.
Меня FreeAndNil настораживает не меньше, чем Application.ProcessMessages. Очень похоже, что у программиста была проблема, для решения которой использовались труднопонимаемые костыли. Скорее всего, все варианты передачи управления он не предусмотрел. Как-то так.
← →
Petr V. Abramov © (2012-06-20 00:45) [50]
> oxffff © (20.06.12 00:38) [48]
>
> Пример нужно.
>
совсем :)
← →
oxffff © (2012-06-20 00:50) [51]
> Sha © (20.06.12 00:45) [49]
Моя вина, я видимо что то пропустил. :)
P.S. Насколько помню, не использовал freeandnil
(2 раза не считается из 100500). Считаю тем не менее, что ее логика возможно кому то пригодится, и не отрицаю freeandnil. Но тем не менее, понимаю, что в сложных циклическим связках, гораздо лучше GC.
← →
Anatoly Podgoretsky © (2012-06-20 07:38) [52]> Sha (20.06.2012 00:45:49) [49]
Это у Борланда была проблема – чтобы еще для ламеров сделать, а то они
неумехи не могут переменную обнулить и вместо нормально решения в стиле ООП
они сделали нетипизированый костыль.
← →
oxffff © (2012-06-20 09:12) [53]
> они сделали нетипизированый костыль.
Нетипизированный он и должен быть - это правильно с точки зрения теории типов.
← →
KSergey © (2012-06-20 14:09) [54]> oxffff © (20.06.12 09:12) [53]
Может таки TObject должен быть тип аргумента?
Иначе фигня получается.
Правда как это относится к теме данного топика - я чета не понимаю.
← →
oxffff © (2012-06-20 15:11) [55]
> KSergey © (20.06.12 14:09) [54]
> > oxffff © (20.06.12 09:12) [53]
>
> Может таки TObject должен быть тип аргумента?
> Иначе фигня получается.
Фигня получается, если параметр будет TObject.
http://pages.cs.wisc.edu/~rkennedy/var-identical
← →
KSergey © (2012-06-20 15:26) [56]> oxffff © (20.06.12 15:11) [55]
> Фигня получается, если параметр будет TObject.
Можно поконкретнее, где там про фигню, относящуюся к FreeAndNil?
Впрочем, как и про любую другую.
← →
oxffff © (2012-06-20 15:43) [57]
> KSergey © (20.06.12 15:26) [56]
Я не Rouse, на дискуссию у меня нет времени.
← →
Kerk © (2012-06-20 15:46) [58]
> KSergey © (20.06.12 15:26) [56]
Попробуй сделать аналог FreeAndNil, принимающий TObject. Сам все поймешь.
← →
oxffff © (2012-06-20 15:48) [59]
> Я не Rouse, на дискуссию у меня нет времени.
Впрочем думаю, что и у Александра его тоже нет.
← →
jack128_ (2012-06-21 00:31) [60]
> Нетипизированный он и должен быть - это правильно с точки
> зрения теории типов.
Это правельно с точки зрения примитивной объект паскалевской системы типов. С дженериками эта процедура должна иметь такую сигнатуру:
procedure FreeAndNil<T:TObject>(var Obj: T);
← →
icWasya © (2012-06-21 09:38) [61]>Sha © (20.06.12 00:45) [49]
>была проблема, для решения которой использовались труднопонимаемые костыли.
Костыль применён, но им не воспользовалисьprocedure TForm1.ChangeConnectionEvent(Sender: TObject);
var fDBConnector:TDBConnector absolute Sender;
begin
if Assigned(fDBConnector) then //<<==--
AddToLog("Nul.") else //<<==--
if fDBConnector.ConnectionState = csDisconnected then
AddToLog("Disconnected.");
end;
← →
KSergey © (2012-06-21 10:46) [62]> Kerk © (20.06.12 15:46) [58]
Короче наследника не дает запихать в var
Так бы и сказали. При чем тут дискуссия??
← →
oxffff © (2012-06-21 12:56) [63]
> Это правельно с точки зрения примитивной объект паскалевской
> системы типов.
Я о том, что у типизированного указателя подтипом является только он сам.
← →
wl © (2012-06-21 13:53) [64]мне кажется это какие-то многопоточные заморочки. чтобы во время работы деструктора другой поток не вздумал пользоваться полуразрушенными данными объекта
← →
KSergey © (2012-06-21 14:14) [65]> wl © (21.06.12 13:53) [64]
Это никак не защищает, сели ссылки - две.
Да второй поток может запросто вызвать какой-то метод объекта, этот метод на середине прервется - и тут поедет выполняться Free
Этому ничего не мешает вообще, это все на совести программиста такие фокусы.
← →
Kerk © (2012-06-21 15:17) [66]В мелкософт есть один чувак (Реймонд Чен?), объясняющий в блоге истоки некоторых исторически сложившихся решений в Windows и в WinAPI вчастности. Интересно было бы подобное из недр Embarcadero почитать. Кто вообще придумал FreeAndNil и почему реализовал именно так :)
← →
Anatoly Podgoretsky © (2012-06-21 15:31) [67]> Kerk (21.06.2012 15:17:06) [66]
Раньше блоги назывались дискуссионные группы новостей, Было Borland News
Groups, там TEAMB обсуждали эту тему, в общем выходило что в основном для
ламеров, пошли на поводу, особенно сильно это было в Д6/7 они столько
функций наплодили, вместо развития языка
Страницы: 1 2 вся ветка
Форум: "Прочее";
Текущий архив: 2013.03.22;
Скачать: [xml.tar.bz2];
Память: 0.62 MB
Время: 0.07 c