Форум: "Прочее";
Текущий архив: 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]> а если код сложный?
> + копи паст?
ошибки надо исправлять, а не прятать
Страницы: 1 2 вся ветка
Форум: "Прочее";
Текущий архив: 2013.03.22;
Скачать: [xml.tar.bz2];
Память: 0.54 MB
Время: 0.078 c