Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Прочее";
Текущий архив: 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
2-1303488855
istok
2011-04-22 20:14
2011.07.31
прочитать строку UTF-8...


2-1303574425
kulon
2011-04-23 20:00
2011.07.31
Как сместить все значения поля на одну строку вниз?


2-1303813642
flincs
2011-04-26 14:27
2011.07.31
Как обрезать белые края изображения


11-1236071712
rvi
2009-03-03 12:15
2011.07.31
Запись в log


15-1302638629
Kerk
2011-04-13 00:03
2011.07.31
"Первая орбита"





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