Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Начинающим";
Текущий архив: 2013.03.22;
Скачать: [xml.tar.bz2];

Вниз

Как избежать разрушения после 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;
Скачать: [xml.tar.bz2];

Наверх




Память: 0.49 MB
Время: 0.055 c
15-1338834689
alexdn
2012-06-04 22:31
2013.03.22
Вот что то мне не верится


2-1343328927
Alez
2012-07-26 22:55
2013.03.22
Microsoft OneNote


15-1332875974
Сергей_С
2012-03-27 23:19
2013.03.22
Проблема в скайпе с отображением видео


15-1352061269
Rouse_
2012-11-05 00:34
2013.03.22
Винлокер


2-1338190785
jacksotnik
2012-05-28 11:39
2013.03.22
Удалить поле из пользовательского датасета





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
Английский Французский Немецкий Итальянский Португальский Русский Испанский