Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2005.11.27;
Скачать: CL | DM;

Вниз

Автоматический вызов деструкторов при выходе из процедуры.   Найти похожие ветки 

 
Владислав ©   (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;
Скачать: CL | DM;

Наверх




Память: 0.51 MB
Время: 0.044 c
14-1131542528
RDA
2005-11-09 16:22
2005.11.27
Компьютерная барахолка в Киеве


14-1131121160
psa247
2005-11-04 19:19
2005.11.27
Замена TaskManager


6-1123928891
0n!k
2005-08-13 14:28
2005.11.27
clientsocket no API ASync Lookup


2-1131538684
Al_Ba
2005-11-09 15:18
2005.11.27
Помогите с TreeView


2-1131443009
pathfinder
2005-11-08 12:43
2005.11.27
Удаление записей в StrinList.