Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Основная";
Текущий архив: 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.019 c
2-1131345790
officeman
2005-11-07 09:43
2005.11.27
Borland Pascal =) Возведение в степень


14-1131181753
Lisa
2005-11-05 12:09
2005.11.27
Помогите с DXF


2-1131802641
Fr3nch
2005-11-12 16:37
2005.11.27
Обращение к динамически созданной метке


14-1130752149
karat
2005-10-31 12:49
2005.11.27
Алгоритмы выявления индентичности предложений?


2-1131714238
De1uxe
2005-11-11 16:03
2005.11.27
Помогите





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский