Форум: "Прочее";
Текущий архив: 2011.07.31;
Скачать: [xml.tar.bz2];
ВнизAfterConstruction, beforedestruction у record Найти похожие ветки
← →
DiamondShark © (2011-04-07 20:41) [40]
> может быть, автоматическое уничтожение потомков TInterfacedObject
> - тоже костыли?
А где есть автоматическое уничтожение потомков TInterfacedObject?
← →
Kerk © (2011-04-07 20:41) [41]
> попробуй несколько экземпляров непотомков TInterfacedObject
> положить в два TObjectList"а.
А почему этого нельзя делать? У TObjectList, если мне не изменяет склероз, в конструкторе есть параметр OwnsObjects, ставишь его в False и клади свои объекты хоть в пять листов.
← →
Kerk © (2011-04-07 20:43) [42]
> DiamondShark © (07.04.11 20:41) [40]
>
> > может быть, автоматическое уничтожение потомков TInterfacedObject
> > - тоже костыли?
>
> А где есть автоматическое уничтожение потомков TInterfacedObject?
>
Видимо это имеется ввидуfunction TInterfacedObject._Release: Integer;
begin
Result := InterlockedDecrement(FRefCount);
if Result = 0 then
Destroy;
end;
← →
_Юрий (2011-04-07 21:14) [43]
> Теперь ситуация №2.
> function TForm1.CreateMyClass: TObject;
> begin
> Result := TMyClass.Create;
> end;
>
> Ответь мне, пожалуйста, в этом коде есть ошибка?
В этом коде нет ошибки.
Пока мы не начали работать с экземпляром как с интерфейсом, никакой подсчет ссылок не ведется, и опасность "самопроизвольного" разрушения отсутствует напрочь, если ты об этом.
← →
_Юрий (2011-04-07 21:26) [44]
> А почему этого нельзя делать? У TObjectList, если мне не
> изменяет склероз, в конструкторе есть параметр OwnsObjects,
> ставишь его в False и клади свои объекты хоть в пять листов.
>
>
По умолчанию параметр равен true. Забыть можно.
А если система большая и связи сложные, и один инстанс регистрируется в разных листах, иной раз вовремя его убить, чтобы никто не обломался позже, становится и вовсе нетривиальной задачей. Решабельной, но требующей дополнительных телодвижений и дополнительного кода. Кстати в таком случае использование механизма саморазрушения является неплохим выходом - мы вообще перестаем заботиться о разрушении, и он гарантинрованно не разрушится, пока о нем хоть кто-то помнит.
Чего в этом плохого?
← →
Kerk © (2011-04-07 21:31) [45]
> _Юрий (07.04.11 21:14) [43]
А ты проверь, чему будет равен RefCount у возвращенного такой функцией объекта (подразумеваем, что он унаследован от TInterfacedObject). Могу сразу сказать, он будет равен нулю.
← →
_Юрий (2011-04-07 21:48) [46]
> Могу сразу сказать, он будет равен нулю.
Ну да, будет равен нулю, это совершенно правильно. На него отсутствуют ссылки как на интерфейс. И он не разрушится, несмотря на RefCount = 0.
Собственно, все написано в его коде.
← →
Kerk © (2011-04-07 22:07) [47]
> _Юрий (07.04.11 21:48) [46]
>
> > Могу сразу сказать, он будет равен нулю.
>
> Ну да, будет равен нулю, это совершенно правильно. На него
> отсутствуют ссылки как на интерфейс. И он не разрушится,
> несмотря на RefCount = 0.
> Собственно, все написано в его коде.
Я не обсуждаю то, что у него в коде написано. В коде ошибок нет, само его существование - ошибка.
Видимо, я действительно слишком издалека зашел.
Вот тебе более конкретный пример, нажми на Button1 более одного раза, посмотри что будет. Закрой форму, посмотри что будет.unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
type
IMyInterface = interface
["{F63315C6-BCF8-435D-86BB-6271FD9D5C93}"]
function GetStr: string;
end;
TMyClass = class(TInterfacedObject, IMyInterface)
public
function GetStr: string;
end;
TForm1 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure FormClose(Sender: TObject; var Action: TCloseAction);
private
{ Private declarations }
Obj: TObject;
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.Button1Click(Sender: TObject);
var
MyIntf: IMyInterface;
begin
if Supports(Obj, IMyInterface, MyIntf) then
ShowMessage(MyIntf.GetStr);
end;
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
Obj.Free;
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
Obj := TMyClass.Create;
end;
{ TMyClass }
function TMyClass.GetStr: string;
begin
Result := "123";
end;
end.
← →
Kerk © (2011-04-07 22:18) [48]Да, первый пример был крайне неудачен. Это у меня голова просто забита своими частностями.
← →
Игорь Шевченко © (2011-04-07 22:20) [49]Давай немножко изменим:
unit main;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
type
IMyIntf = interface
["{CAE63E79-F4F6-4B49-A235-223546249CD7}"]
function GetStr: string;
end;
TFoo = class(TInterfacedObject, IMyIntf)
private
function GetStr: string;
end;
TForm1 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure FormClose(Sender: TObject; var Action: TCloseAction);
private
FObj: IUnknown;
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.Button1Click(Sender: TObject);
var
MyIntf: IMyIntf;
begin
if Supports(FObj, IMyIntf, MyIntf) then
ShowMessage(MyIntf.GetStr);
end;
{ TFoo }
function TFoo.GetStr: string;
begin
Result := "Foo";
end;
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
FObj := nil;
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
FObj := TFoo.Create;
end;
end.
← →
_oxffff (2011-04-08 08:55) [50]
> Kerk © (07.04.11 22:07) [47]
Я перепишу твой пример до более короткого.
procedure Kill(intf:IUnknown);
begin
end;
procedure TForm5.Button1Click(Sender: TObject);
var obj:TInterfacedObject;
begin
obj:=TInterfacedObject.create;
Kill(obj);
obj.ToString; // <-
end;
← →
reonid © (2011-04-08 11:27) [51]2Kerk ©
>В коде ошибок нет, само его существование - ошибка.
Для объекта (точнее, переменной типа объект, т.е. объектной ссылки!)
вовсе не является ошибкой существование с RefCount = 0.
Более того, наоборот, скорее всего будет ошибкой RefCount <> 0.
← →
_Юрий (2011-04-08 18:57) [52]
> Kerk © (07.04.11 22:07) [47]
> Вот тебе более конкретный пример
Есть некотоыре базовые вещи, которые программист на delphi знать обязан. Например, что созданный объект надо разрушить.
Или например то, что ручное разрушение объекта, который был уже запрошен как интерфейс - это хождение по минному полю. И дело тут не в том, как он реализован - с авторазрущением или без (ничто не мешает нам перекрыть _Release и не разрушать объект при обнулении счетчика). Дело в том, что любая забытая где-либо интерфейсная ссылка на этот объект приведет к проблемам при финализации, если объект уже разрушен руками.
Надо просто понимать, что делаешь
← →
Kerk © (2011-04-08 19:09) [53]
> _Юрий (08.04.11 18:57) [52]
У тебя универсальный подход к любой кривизне: "надо просто ее учитывать и проблем не будет". Ну флаг в руки, чего еще сказать :)
← →
Игорь Шевченко © (2011-04-08 19:17) [54]
> У тебя универсальный подход к любой кривизне: "надо просто
> ее учитывать и проблем не будет".
во-первых, весьма, кстати, разумный подход. во-вторых, а в чем кривизна ?
← →
Kerk © (2011-04-08 19:25) [55]
> Игорь Шевченко © (08.04.11 19:17) [54]
>
> > У тебя универсальный подход к любой кривизне: "надо просто
> > ее учитывать и проблем не будет".
>
> во-первых, весьма, кстати, разумный подход.
Ну да. Жри, что дают.
С реальностью я сам не спорю, что не мешает мне ее критиковать.
> во-вторых, а в чем кривизна ?
Кривизна в том, что интерфейсы к Delphi были прикручены сбоку специально для поддержки COM и для других применений мало приспособлены. В [47] в классическом ООПшном смысле ошибок нет. Тем не менее, имеем что имеем.
← →
_Юрий (2011-04-08 19:26) [56]
> Kerk © (08.04.11 19:09) [53]
У меня есть знакомый прогрммист, который утверждает, что XML - отвратительно неудобный отстой, и в него очень неудобно записывать данные. Потому что легко запутаться и нарушить структуру докумена, забыв например закрывающий тег.
Расследование показало, что он формирует содержимое руками, по типу
StringList.Add("<" + val1 + ">" + val12 + "<" + va1 + "/>");
StringList.SaveToFile(filename);
Думаешь, мне удалось ему что-либо доказать?
← →
Kerk © (2011-04-08 19:31) [57]
> _Юрий (08.04.11 19:26) [56]
Я понимаю, что ты 110% уверен в своей правоте, но ты пытался хотя бы задуматься о том, что я говорю?
← →
_Юрий (2011-04-08 19:39) [58]
> Kerk © (08.04.11 19:31) [57]
Ты отчасти прав. В делфи эта кухня действительно реализована отвратительно. А в том, что это нельзя использовать нигде кроме COM, ты не прав. Использовать можно и нужно, потому, что ничего другого судя по всему не будет, а интерфейсы даже в таком виде способны прекрасно помочь.
← →
Kerk © (2011-04-08 19:45) [59]
> _Юрий (08.04.11 19:39) [58]
Дык чего ж мы тогда спорим. Тут мне возразить нечему.
← →
reonid © (2011-04-08 19:45) [60]2Kerk © (08.04.11 19:25) [55]
Довольно просто было бы реализовать интерфейсы без автоматического уничтожения.
И обязать всех программистов вручную вызывать _AddRef и _Release,
как это реализовано в некоторых языках.
Это не составляет никакой технической трудности.
И все Ваши претензии были бы удовлетворены.
Вопрос, стало бы от этого меньше проблем?
← →
_Юрий (2011-04-08 19:47) [61]
> Kerk © (08.04.11 19:45) [59]
Да, забавно )
← →
DiamondShark © (2011-04-08 19:48) [62]
> Kerk © (08.04.11 19:25) [55]
Вот тебе более конкретный пример, посмотри что будет.
var
x, y: Integer;
begin
x := 2147483647;
y := x + 1;
writeln(y);
end.
Кривизна в том, что целые числа к Delphi были прикручены сбоку специально для поддержки CPU и для других применений мало приспособлены. В классическом арифметическом смысле ошибок нет. Тем не менее, имеем что имеем.
← →
_Юрий (2011-04-08 19:52) [63]
> reonid © (08.04.11 19:45) [60]
> Вопрос, стало бы от этого меньше проблем?
Тут проблема в другом - в том, что программиста вообще заставляют реализовывать эти три метода, в то время как ему нужен только прикладной четвертый метод.
Я вот хочу, чтобы все объекты отдавали мне например DisplayName: string;
И при чем тут еще три метода?
Грубо говоря, класс должен тут же ответить на вопрос - а "Как я буду разрушаться? Автоматически или нет?"
А сам класс этого в общем случае не знает. Это скорее всего знает тот, кто инстанцирует.
А тут получается наоборот - на этот вопрос отвечает класс, а инстанцирующий сдедовательно должен оьязательно знать о деталях реализации интерфейса, получаем нарушение инкапсуляции.
Как то так
← →
Kerk © (2011-04-08 19:55) [64]Удалено модератором
← →
Kerk © (2011-04-08 19:58) [65]
> _Юрий (08.04.11 19:52) [63]
Да, счетчик ссылок не всегда нужен. Тут примером может выступать TComponent, где счетчик ссылок работает иначе.
← →
reonid © (2011-04-08 20:06) [66]2_Юрий (08.04.11 19:52) [63]
Можно было бы сделать и такую реализацию интерфейсов.
Без управляемого времени жизни.
С пустым базовым интерфеисом, от которого бы наследовался IUnknown.
И с СОМом работать, не забывая вручную вызывать _AddRef и _Release.
То, что сделали не так, это было осознанное решение с целью минимизации геморроя.
← →
DiamondShark © (2011-04-08 20:09) [67]
> Kerk © (08.04.11 19:55) [64]
Надеюсь, ты отдаёшь себе отчёт, что практически любую языковую фичу можно использовать нештатным образом.
Объясни, пожалуйста, почему в одном случае ты это считаешь кривизной (языка, а не собственных рук), а в другом -- нет. У тебя ФГМ?
← →
_Юрий (2011-04-08 20:15) [68]
> reonid © (08.04.11 20:06) [66]
Надо было сделать базовый - пустой IInterface, и IUnknown c автоматическим подсчетом ссылок, и наследовать наоборот IUnknown от IInterface.
Тогда было бы все хорошо.
← →
reonid © (2011-04-08 20:23) [69]2_Юрий (08.04.11 20:15) [68]
И получили бы те же грабли, только в профиль.
Запрашиваешь у неуправляемого интерфейса IUnknown,
и всё - объект помер.
← →
_Юрий (2011-04-08 20:28) [70]
> reonid © (08.04.11 20:23) [69]
Ну в общем да, только тогда эти грабли были бы необязательными, потому что необязательно запрашивать IUnknown.
А с нынешним положением дел они обязательные
← →
DiamondShark © (2011-04-08 20:29) [71]
> reonid © (08.04.11 20:23) [69]
По крайней мере, можно было бы чётко разделить COM-овские интерфейсы, и внутренние интерфейсы.
← →
reonid © (2011-04-08 20:37) [72]2DiamondShark © (08.04.11 20:29) [71]
Сейчас хотя бы на глаз легко отличить ob: TMyObject от intf: IMyInterface
А так поди, догадайся, какой из intf1: IMyInterface1 и intf2: IMyInterface2
управляемый, а какой - нет.
← →
reonid © (2011-04-08 20:39) [73]Не говоря уж, что небольшой заменой кода можно легко преобразовать
один тип поведения в другой (добавив в список предков IUnknown, или убрав),
и получить довольно непредсказуемые последствия.
← →
DiamondShark © (2011-04-08 20:51) [74]
> reonid © (08.04.11 20:37) [72]
Сейчас приходится помнить гораздо больше вещей.
> reonid © (08.04.11 20:39) [73]
Изменением предка вообще можно чудес натворить.
Радикальное решение -- только полностью управляемые языки.
В гибридных языках всегда будет что-то выпирать.
← →
Kerk © (2011-04-08 21:46) [75]
> DiamondShark ©
По последним постам вижу, что наконец до тебя дошло о чем речь. Поздравляю. Так бы сразу.
← →
DiamondShark © (2011-04-08 22:42) [76]Удалено модератором
← →
Димка На (2011-04-09 21:26) [77]При присваивании записи она должна вновь инициализироваться?
← →
oxffff © (2011-04-10 12:51) [78]
> Димка На (09.04.11 21:26) [77]
> При присваивании записи она должна вновь инициализироваться?
>
Нет. Это не инициализатор, и не финализатор.
← →
Дмитрий С © (2011-04-11 08:44) [79]
> Нет. Это не инициализатор, и не финализатор.
А что тогда? в чем предназначение?
← →
_oxffff (2011-04-11 09:50) [80]
> Дмитрий С © (11.04.11 08:44) [79]
>
> > Нет. Это не инициализатор, и не финализатор.
>
> А что тогда? в чем предназначение?
Это события экземпляра типа, о том что экземпляр аллокировался и о том, что экземпляр разрушается.
Страницы: 1 2 3 вся ветка
Форум: "Прочее";
Текущий архив: 2011.07.31;
Скачать: [xml.tar.bz2];
Память: 0.63 MB
Время: 0.008 c