![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Как избежать разрушения после TMyIoClass.Destroy.
Наивный © (2012-08-19 12:58:00)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 ?*) и, ели да, то для чего?
bems (2012-08-23 11:18:00) [1]В сообщении выше везде где я говорю про конструктор, имеется в виду деструктор, конечно же
bems (2012-08-23 11:11:00) [2]
> Наивный (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;
Но про то что нельзя вызывать конструктор напрямую это тоже соглашения, так что по сути легче от этого способа не становится
sniknik (2012-08-22 16:50:00) [3]хотя... неизвестно еще кто ламер, если для чьегото творения требуется нестандартное завершение... вот в дельфе у форм все понятно, и по другому/лучше вряд ли получится. а у тебя еще вопрос. и мы до сих пор не обсуждаем источника проблем, только последствия от действий в нем.
sniknik (2012-08-22 16:45:00) [4]> Да, но сложно проконтролировать выполнения этого соглашения.
зачем контролировать? в дельфе для форм прописали в ст=правке и все... никто ламеров от себя спасать не собирается.
Наивный (2012-08-22 15:23:00) [5]> bems © (21.08.12 05:56) [6]
Спасибо, из проблем пока увидел то, что деструкторы могут быть вызваны несколько раз.
> bems © (21.08.12 17:17) [9]
> Достаточно просто ввести соглашение что пользовательский код не
> вызывает деструктор а только метод Release
Да, но сложно проконтролировать выполнения этого соглашения.
Поэтому реализую оба варианта, а соглашение о Release дополню фразой
"В противном случае деструкторы производных классов должны быть
спроектированы с учетом повторного вызова."
P.S.
Как-то г-н Давайте будем жрать! в ответ на мой вопрос о FreeAndNil сказал, -
> Free — метод статический (и это хорошо).
Может ли кто-нибудь раскрыть подтверждающие аргументы ?
Спасибо.
bems (2012-08-21 17:17:00) [6]Тут да, нужно считать ссылки, но интерфейсы не обязательны. Достаточно просто ввести соглашение что пользовательский код не вызывает деструктор, а только метод Release
Григорьев Антон (2012-08-21 16:21:00) [7]Ну, тут просто просятся интерфейсы и управление временем жизни объекта через них. Одна ссылка в основной программе, вторая - в потоке, который освобождает объект. Как только счётчик ссылок стал равен 1, значит, программа освободила все свои ссылки на объект, можно начинать удалять его в IoCP-нити, у которой осталась последняя ссылка.
icWasya (2012-08-21 09:27:00) [8]>bems © (21.08.12 05:56) [6]
>Возможность такая есть - ... Но ... это источник проблем
Это как раз проблема XYZ: Нужно сделать X, пытаемся сделать через Y, а решение - Z
bems (2012-08-21 05:56:00) [9]Возможность такая есть - перекрыть FreeInstance. Но не надо так делать, это источник проблем
sniknik (2012-08-20 08:05:00) [10]нет такой возможности, и смысла в ней не... разрушение, разрушает. либо сразу либо с задержкой, в порядке очереди сообщений (чтобы обработчики завершились, т.к. в них может быть ссылка на объект).
> В основном потоке сказали объекту Free, и закрыли хендл связанный с портом завершения ввода/вывода, что пробудило IoCP поток, у которого есть адрес объекта.
идиотизм. на завершении все должно завершатся, а не начинаться. а если завершение одного порождает другое, по логике, то оно должно быть независимо от первого.
у тебя же, раз есть ссылки на объект "родитель", и нужно ждать завершения потомка, объект еще не доработал до конца чтобы его уничтожать. в другом месте нужно.
Наивный (2012-08-20 03:03:00) [11]Извините, я в контекстной смотрел а не поиском:
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-19 19:54:00) [12]> ключевые слова для поиска в help'е
Destroy
> и программа у меня консольная, - или это не меняет сути?
смотря как у тебя оно сделано... но судя по всему не "линейно" раз проблемы с освобождением отработавшего объекта.
а раз так, читай и смотри как сделано.
Наивный (2012-08-19 17:19:00) [13]> прочитай хелп по Destroy для форм
Подскажите, пожалуйста, ключевые слова для поиска в help'е
и программа у меня консольная, - или это не меняет сути?
sniknik (2012-08-19 16:10:00) [14]> что посоветуете?
прочитай хелп по Destroy для форм, вникни в предупреждение... разберись почему.