Форум: "Основная";
Текущий архив: 2005.11.27;
Скачать: [xml.tar.bz2];
ВнизАвтоматический вызов деструкторов при выходе из процедуры. Найти похожие ветки
← →
Владислав © (2005-11-03 11:06) [0]Продолжаем академические исследования :)
Ну тема ясна, остальное есть в примере кода.
Читайте комментарии.
type
TAutoObject = class(TInterfacedObject)
public
// Обязательные методы
// Коструктор, который нам нужен, чтобы обеспечить автоматический вызов деструктора
constructor CreateAuto(var Unknown: IUnknown);
// Необязательные методы (для демонстрации примеров)
// О деструкторе есть подробности, но чуть позже
destructor Destroy; override;
// Здесь выдадим сообщение, что конструктор вызвался
procedure AfterConstruction; override;
// Здесь выдадим сообщение, что деструктор вызвался
procedure BeforeDestruction; override;
end;
{ TAutoObject }
constructor TAutoObject.CreateAuto(var Unknown: IInterface);
begin
// Сначала ничего необычного
inherited Create;
// А дальше вот что:
// Увеличили счетчик ссылок на Self, теперь равен 2
Unknown := Self;
// Вернули счетчик ссылок, теперь равен 1
_Release;
end;
procedure TAutoObject.AfterConstruction;
begin
// Конструктор вызвался
ShowMessage("AfterConstruction")
end;
procedure TAutoObject.BeforeDestruction;
begin
// Деструктор вызвался
ShowMessage("BeforeDestruction")
end;
procedure DoSomething1;
begin
// Что-то делаем
end;
procedure DoSomething2;
begin
// Что-то делаем
end;
// Пример "обычного" создания объектов с использованием try...finally
procedure TestSimpleObject;
var
AutoObject1: TAutoObject;
AutoObject2: TAutoObject;
AutoObject3: TAutoObject;
begin
AutoObject1 := TAutoObject.Create;
try
AutoObject2 := TAutoObject.Create;
try
AutoObject3 := TAutoObject.Create;
try
DoSomething1;
raise Exception.Create("Test destructor call automatically");
DoSomething2;
finally
AutoObject3.Free
end
finally
AutoObject2.Free
end
finally
AutoObject1.Free
end
end;
// Пример создания объектов с использованием TAutoObject.CreateAuto
// Код процедуры выполняет работу, аналогичную TestSimpleObject
procedure TestAutoObject;
var
// Те же переменные, что и в TestSimpleObject
AutoObject1: TAutoObject;
AutoObject2: TAutoObject;
AutoObject3: TAutoObject;
// Это оверхед, но он позволяет автоматически вызвать деструктор
AutoObjectUnk1: IUnknown;
AutoObjectUnk2: IUnknown;
AutoObjectUnk3: IUnknown;
begin
AutoObject1 := TAutoObject.CreateAuto(AutoObjectUnk1);
AutoObject2 := TAutoObject.CreateAuto(AutoObjectUnk2);
AutoObject3 := TAutoObject.CreateAuto(AutoObjectUnk3);
DoSomething1;
raise Exception.Create("Test destructor call automatically");
DoSomething2;
end;
procedure TestAutoAndSimpleObject;
begin
try
TestSimpleObject;
except
end;
try
TestAutoObject;
except
end;
end;
// Вроде бы все удобно. Никакой вложенности try...finally.
// Однако можно огрести вот такую "плюху"
// При возникновении исключения в деструкторе,
// не все автообъекты могут быть освобождены
destructor TAutoObject.Destroy;
begin
// raise Exception.Create("А что будет в этом случае?");
inherited;
end;
Кто, что думает по этому поводу? :)
← →
Игорь Шевченко © (2005-11-03 11:11) [1]
> Автоматический вызов деструкторов при выходе из процедуры
> Кто, что думает по этому поводу? :)
интерфейсы не проще использовать ? у них reference counting поддерживается компилятором
← →
TUser © (2005-11-03 11:22) [2]А если ты введешь глобальную переменную (и не надо говорить, что они маст дай :), и присвоишь ей значение вот так
var Global: TAutoObject;
procedure TestAutoObject;
var
// Те же переменные, что и в TestSimpleObject
AutoObject1: TAutoObject;
AutoObject2: TAutoObject;
AutoObject3: TAutoObject;
// Это оверхед, но он позволяет автоматически вызвать деструктор
AutoObjectUnk1: IUnknown;
AutoObjectUnk2: IUnknown;
AutoObjectUnk3: IUnknown;
begin
AutoObject1 := TAutoObject.CreateAuto(AutoObjectUnk1);
AutoObject2 := TAutoObject.CreateAuto(AutoObjectUnk2);
AutoObject3 := TAutoObject.CreateAuto(AutoObjectUnk3);
Global:=AutoObject2;
DoSomething1;
// raise Exception.Create("Test destructor call automatically");
DoSomething2;
end;
То при вызове такой процедуры все равно произойдет вызов деструктора. Счетчик ссылок на интерфейс-то ведь не поменялся. И глобальная переменная будет указывать в никуда. И будет нехорошо.
← →
Набережных С. © (2005-11-03 11:24) [3]
> Кто, что думает по этому поводу? :)
Откровенно? Ерунда. Банальное смешивание интерфейсных и объектных ссылок, которое рано или поздно выйдет боком. Да и не нужен тут никакой CreateAuto:
TExampleObject = class(TInterfacedObject)
procedure DoSometshing;
end;
procedure Example;
var
O: TExampleObject;
I: IInterface;
begin
O:=TExampleObj.Create;
I:=O;
O.DoSometshing;
end;
Тот же результат.
← →
jack128 © (2005-11-03 11:25) [4]Владислав © (03.11.05 11:06)
// При возникновении исключения в деструкторе,
Это недопустимо. Ты то можешь конечно поднять исключение, но в любом случае(не только в твоем) это черевато крупными проблемами, AV"ки посыпятся везде и всюду, а если учесть что народ большей частью вложенные объекты в деструкторе уничтожает так:
destructor TSomeObj.Destroy;
begin
FSubObj.Free;
inherited;
end;
это еще и ОЧЕНЬ трудно обнаруживаемые AV"ки
А для того чтобы избежать большой вложенности try-finally я делаю так:var
SomeObj1, SomeObj2, SomeObj3: Tobject;
begin
SomeObj1 := nil; SomeObj2 := nil; SomeObj3 := nil;
try
....
finally
FreeAndNil(SomeObj1);
FreeAndNil(SomeObj2);
FreeAndNil(SomeObj3);
end;
end;
← →
Sergey_Masloff (2005-11-03 11:36) [5]jack128 © (03.11.05 11:25) [4]
var
SomeObj1, SomeObj2, SomeObj3: Tobject;
begin
SomeObj1 := nil; SomeObj2 := nil; SomeObj3 := nil;
try
....
finally
FreeAndNil(SomeObj1); ====> Тут ловим исключение. Что дальше?
FreeAndNil(SomeObj2);
FreeAndNil(SomeObj3);
end;
end;
← →
jack128 © (2005-11-03 11:55) [6]Sergey_Masloff (03.11.05 11:36) [5]
FreeAndNil(SomeObj1); ====> Тут ловим исключение. Что дальше?
jack128 © (03.11.05 11:25) [4]
// При возникновении исключения в деструкторе,
Это недопустимо
Мое вот такое мнение ;)
← →
Sergey_Masloff (2005-11-03 11:59) [7]jack128 © (03.11.05 11:55) [6]
>Мое вот такое мнение ;)
Твое мнение бы да некоторым разработчикам в уши... Намного легче б жить стало
← →
Владислав © (2005-11-03 12:10) [8]
> Игорь Шевченко © (03.11.05 11:11) [1]
>
> интерфейсы не проще использовать ? у них reference counting
> поддерживается компилятором
Нужно будет описывать интерфейс на каждый класс и одинаковые методы в интерфейсе и классе.
> TUser © (03.11.05 11:22) [2]
Это будет недопустимо и равносильно сохранению в глобальную переменную указателя на локальную переменную.
> Набережных С. © (03.11.05 11:24) [3]
>
> Откровенно? Ерунда. Банальное смешивание интерфейсных и
> объектных ссылок, которое рано или поздно выйдет боком.
Где зло кроется? :)
> Набережных С. © (03.11.05 11:24) [3]
> Да и не нужен тут никакой CreateAuto:
>
> TExampleObject = class(TInterfacedObject)
> procedure DoSometshing;
> end;
>
> procedure Example;
> var
> O: TExampleObject;
> I: IInterface;
> begin
> O:=TExampleObj.Create;
> I:=O;
> O.DoSometshing;
> end;
>
> Тот же результат.
Согласен. То же самое другим способом. Единственное, что можно сказать, в моем способе присутствует большая явность того, что экземпляр будет освобождаться автоматически.
> jack128 © (03.11.05 11:25) [4]
> Это недопустимо. Ты то можешь конечно поднять исключение,
> но в любом случае(не только в твоем) это черевато крупными
> проблемами, AV"ки посыпятся везде и всюду, а если учесть
Хммм... Я вероятно что-то недопонимаю в деструкторах... Но пример отрабатывает без проблем, при исключении в деструкторе. В чем суть?
> jack128 © (03.11.05 11:25) [4]
>
> А для того чтобы избежать большой вложенности try-finally
> я делаю так:
>
> var
> SomeObj1, SomeObj2, SomeObj3: Tobject;
> begin
> SomeObj1 := nil; SomeObj2 := nil; SomeObj3 := nil;
> try
> ....
> finally
> FreeAndNil(SomeObj1);
> FreeAndNil(SomeObj2);
> FreeAndNil(SomeObj3);
> end;
> end;
Интересно...
P.S. Я не спорю, я просто вслух рассуждаю...
← →
Владислав © (2005-11-03 12:13) [9]
> Sergey_Masloff (03.11.05 11:59) [7]
> jack128 © (03.11.05 11:55) [6]
> >Мое вот такое мнение ;)
> Твое мнение бы да некоторым разработчикам в уши... Намного
> легче б жить стало
ПМСМ с такими мыслями лучше вообще программы не начинать писать :)
← →
jack128 © (2005-11-03 12:13) [10]Владислав © (03.11.05 12:10) [8]
Но пример отрабатывает без проблем, при исключении в деструкторе. В чем суть?
В твоем примере при исключении ты мемлик получаешь. объект то не уничтожен, а ссылку на него ты потерял.
← →
Владислав © (2005-11-03 12:29) [11]
> jack128 © (03.11.05 12:13) [10]
> > Владислав © (03.11.05 12:10) [8]
> > Но пример отрабатывает без проблем, при исключении в деструкторе.
> > В чем суть?
>
> В твоем примере при исключении ты мемлик получаешь. объект
> то не уничтожен, а ссылку на него ты потерял.
Ну если учесть, что:
jack128 © (03.11.05 11:55) [6] "Это недопустимо"
то вполне работоспособный код :)
Страницы: 1 вся ветка
Форум: "Основная";
Текущий архив: 2005.11.27;
Скачать: [xml.tar.bz2];
Память: 0.49 MB
Время: 0.012 c