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

Вниз

Как избежать разрушения после TMyIoClass.Destroy.   Найти похожие ветки 

 
Наивный   (2012-08-19 12:58) [0]

XE2, W7
Есть класс с асинхронной логикой работы (сокеты на IoCP), использование которого для "пользователя" хотелось бы сделать классическим – вызов Free или Destroy когда захочется.

Проблема в том, что после TMyIoClass.Destroy объект разрушается в независимости от того был вызван inherited Destroy или нет. Но объект дальше еще нужен для корректного завершения на IoCP, откуда и будет выполнена зачистка.

Раньше эта "логика" (как-бы двойное уничтожения объекта) было реализовано в TMyIoClass.Free через inherited Free и меня удовлетворяло.

Но оказалось, что возможны легальные ситуации, когда TMyIoClass.Free не будет вызван "пользователем" (например если FreeAndNil или Destroy), поэтому перенес "логику" в Destroy; override; и напроролся уже не на виртуальную ;) , а на реальную проблему.

Как быть, что посоветуете?

P.S.
Используете ли Вы в своих классах procedure Free; (* virtual ?*)  и, ели да, то для чего?


 
sniknik ©   (2012-08-19 16:10) [1]

> что посоветуете?
прочитай хелп по Destroy для форм, вникни в предупреждение... разберись почему.


 
Наивный   (2012-08-19 17:19) [2]

> прочитай хелп по Destroy для форм
Подскажите, пожалуйста, ключевые слова для поиска в help"е
и программа у меня консольная, - или это не меняет сути?


 
sniknik ©   (2012-08-19 19:54) [3]

> ключевые слова для поиска в help"е
Destroy

> и программа у меня консольная, - или это не меняет сути?
смотря как у тебя оно сделано... но судя по всему не "линейно" раз проблемы с освобождением отработавшего объекта.
а раз так, читай и смотри как сделано.


 
Наивный   (2012-08-20 03:03) [4]

Извините, я в контекстной смотрел а не поиском:

Do not explicitly destroy form objects. Instead, use the Release method to free a form. Release waits until all event handlers have finished executing before destroying the form.


Это я понял или частично понял, потому что waits не вяжется с PostMessage и у меня еще и несколько потоков, а тут один сам себе забрасывает задание.

Да, я тоже могу организовать очередь управляющих действий со своим Release, но исходя из первого абзаца [0], решил разрешить использовать TObject.Free -> TMyClass.Destroy.

> не "линейно"  :
В основном потоке сказали объекту Free, и закрыли хендл связанный с портом завершения ввода/вывода, что пробудило IoCP поток, у которого есть адрес объекта. А объекта уже и нет. ):

Поэтому нужно иметь возможность при некотором условии не разрушить объект в TMyClass.Destroy.
Если такая возможность есть - подскажите.


 
sniknik ©   (2012-08-20 08:05) [5]

нет такой возможности, и смысла в ней не... разрушение, разрушает. либо сразу либо с задержкой, в порядке очереди сообщений (чтобы обработчики завершились, т.к. в них может быть ссылка на объект).

> В основном потоке сказали объекту Free, и закрыли хендл связанный с портом завершения ввода/вывода, что пробудило IoCP поток, у которого есть адрес объекта.
идиотизм. на завершении все должно завершатся, а не начинаться. а если завершение одного порождает другое, по логике, то оно должно быть независимо от первого.
у тебя же, раз есть ссылки на объект "родитель", и нужно ждать завершения потомка, объект еще не доработал до конца чтобы его уничтожать. в другом месте нужно.


 
bems ©   (2012-08-21 05:56) [6]

Возможность такая есть - перекрыть FreeInstance. Но не надо так делать, это источник проблем


 
icWasya ©   (2012-08-21 09:27) [7]

>bems ©   (21.08.12 05:56) [6]
>Возможность такая есть - ... Но ... это источник проблем
Это как раз проблема XYZ: Нужно сделать X, пытаемся сделать через Y, а решение - Z


 
Григорьев Антон ©   (2012-08-21 16:21) [8]

Ну, тут просто просятся интерфейсы и управление временем жизни объекта через них. Одна ссылка в основной программе, вторая - в потоке, который освобождает объект. Как только счётчик ссылок стал равен 1, значит, программа освободила все свои ссылки на объект, можно начинать удалять его в IoCP-нити, у которой осталась последняя ссылка.


 
bems ©   (2012-08-21 17:17) [9]

Тут да, нужно считать ссылки, но интерфейсы не обязательны. Достаточно просто ввести соглашение что пользовательский код не вызывает деструктор, а только метод Release


 
Наивный   (2012-08-22 15:23) [10]

> bems ©   (21.08.12 05:56) [6]
Спасибо, из проблем пока увидел то, что деструкторы могут быть вызваны несколько раз.

> bems ©   (21.08.12 17:17) [9]
> Достаточно просто ввести соглашение что пользовательский код не
> вызывает деструктор а только метод Release
Да, но сложно проконтролировать выполнения этого соглашения.

Поэтому реализую оба варианта, а соглашение о Release дополню фразой
"В противном случае деструкторы производных классов должны быть
спроектированы с учетом повторного вызова."

P.S.
Как-то г-н Давайте будем жрать! в ответ на мой вопрос о FreeAndNil сказал, -
> Free — метод статический (и это хорошо).
Может ли кто-нибудь раскрыть подтверждающие аргументы ?
Спасибо.


 
sniknik ©   (2012-08-22 16:45) [11]

> Да, но сложно проконтролировать выполнения этого соглашения.
зачем контролировать? в дельфе для форм прописали в ст=правке и все... никто ламеров от себя спасать не собирается.


 
sniknik ©   (2012-08-22 16:50) [12]

хотя... неизвестно еще кто ламер, если для чьегото творения требуется нестандартное завершение... вот в дельфе у форм  все понятно, и по другому/лучше вряд ли получится. а у тебя еще вопрос. и мы до сих пор не обсуждаем источника проблем, только последствия от действий в нем.


 
bems ©   (2012-08-23 11:11) [13]


> Наивный   (22.08.12 15:23) [10]

Можно избежать повторного вызова конструкторов унаследованных классов, если не используется прямой вызов конструктора, а только Free или FreeAndNil

Как-то так:  TA = class
 strict private
   FDestroyCount: Integer;
 strict protected
   procedure InternalDestroy; virtual; abstract;
   function AllowDestruction: Boolean;
 public
   destructor Destroy; override;
 end;

 TB = class(TA)
 strict private
   FInInternalDestroy: Boolean;
 strict protected
   procedure InternalDestroy; override;
 public
   destructor Destroy; reintroduce; virtual;
   procedure FreeInstance; override;
 end;

 TUser = class(TB)
 public
   destructor Destroy; override;
 end;

implementation

{$R *.dfm}

{ TA }

function TA.AllowDestruction: Boolean;
begin
 Result := FDestroyCount > 1;
 writeln("FDestroyCount = ", FDestroyCount)
end;

destructor TA.Destroy;
begin
 Inc(FDestroyCount);
 if AllowDestruction
    then InternalDestroy;
end;

{ TB }

procedure TB.FreeInstance;
begin
 if AllowDestruction and not FInInternalDestroy
    then begin
         inherited;
         writeln("inherited TA.FreeInstance")
         end;
end;

destructor TB.Destroy;
begin
 writeln("TB.Destroy");
 inherited;
end;

procedure TB.InternalDestroy;
begin
 if not FInInternalDestroy
    then begin
         FInInternalDestroy := True;
         try
           Destroy
         finally
           FInInternalDestroy := False
         end;
         end;
end;

{ TUser }

destructor TUser.Destroy;
begin
 writeln("TUser.Destroy");
 inherited;
end;


Но про то что нельзя вызывать конструктор напрямую это тоже соглашения, так что по сути легче от этого способа не становится


 
bems ©   (2012-08-23 11:18) [14]

В сообщении выше везде где я говорю про конструктор, имеется в виду деструктор, конечно же



Страницы: 1 вся ветка

Текущий архив: 2013.03.22;
Скачать: CL | DM;

Наверх




Память: 0.51 MB
Время: 0.049 c
15-1351507682
ClawClaw
2012-10-29 14:48
2013.03.22
Мастерам раскрутки сайтов


15-1328106688
3asys
2012-02-01 18:31
2013.03.22
Нужен разработчик имеющий опыт работы со звуком и http


15-1336595403
Юрий
2012-05-10 00:30
2013.03.22
С днем рождения ! 10 мая 2012 четверг


2-1328354340
ParkWay
2012-02-04 15:19
2013.03.22
IntPower/Power не возводит десятичную дробь


2-1333615730
Yl2011
2012-04-05 12:48
2013.03.22
Использование TCanvas для определения размера шрифта