Форум: "Начинающим";
Текущий архив: 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.066 c