![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
"Устаревший стиль объекта" [D7]
Key © (2007-10-13 09:56:00)Уважаемые мастера
Работаю с нек. компонентом. В нем приходится работать с записями. Сообщаешь ему размер этой записи, он сам ее путем GetMem() у себя формирует, куда надо вставляет и когда надо, возвращает на нее указатель. При разрушении - вызывает FreeMem()
Также у этого хитрого компонента предусмотрены события InitItem и FreeItem, выполняющие функции конструктора и деструктора соответственно. Не знаю, почему так, не спрашивайте. :)
Работает нормально, но после работы с классами очень неуютно чувствуешь себя с record. Ни тебе метод написать, ни свойство. Появилась идея заменить record на .... "устаревший" object. Что интересно, работает нормально тоже. И даже свойство вызывается. И память чистится правильно. Фактически это аналог экземпляра класса в C++ (не указателя на него, а расположенного, скажем, в стеке). Разве что конструкторы и деструкторы не вызываются :(
Но Delphi меня начало предупреждать, что мол
"Unsafe type 'TXSDTreeRec: old style object'"
Значит ли это, что пользоваться object нельзя потому, что их поддержка в следующих версиях отсутствует? Или работа их не гарантируется? Или еще какие-то подводные камни?
Спасибо.
просто так (2007-10-16 14:06:00) [1]>>Sapersky
Убедил. у меня AV нету но в s мусор...
я проверял в консольном приложении, в s всё ок, но при добавлении полей в TFirstObj тоже появился мусор. сыплюголову пеплом)))
делаю большой проект на обжектах, ниразу с этим не сталкивался, т.к. не использую локальные сложные переменные
DVM (2007-10-16 11:53:00) [2]
> просто так (16.10.07 07:10) [8]
> >>у меня в BDS2006 один модуль как то не хотел компилироваться,
> потому, что там вместо class было объявлено object.
> думаю причины были совсем не в object. с ними всё ок в BDS2006.
>
Может и не в object, но скомпилировался, только после замены на class.
Вот он кстати (модуль не мой). http://dvmuratov.narod.ru/CpuInfo.pas
Вот в таком виде он не компилируется.
Sapersky (2007-10-16 10:25:00) [3]Какой Delphi? У меня в 5-м AV.
Код полностью:
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls;
type
TForm1 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
TFirstObj = object
s : String;
end;
TSecondObj = object (TFirstObj)
end;
var
Form1: TForm1;
implementation
{$R *.DFM}
procedure TForm1.Button1Click(Sender: TObject);
Var fObj : TFirstObj;
sObj : TSecondObj;
begin
fObj.s := '1';
sObj.s := '2';
end;
end.
просто так (2007-10-16 10:06:00) [4]Специально токачто попробовал вышеизложенный пример завернутый в процедуру. всё работает. если переменная объявлена в var секции она инициализируется корректно и TSecondObj прекрасно знает об s. проблемы могут возникнуть только при динамическом создании, для их решения можно завести отдельный конструктор который будет делать принудительное pointer(s):=nil;
Sapersky (2007-10-16 09:59:00) [5]Я же писал: TSecondObj ничего не знает об s : String; и не сможет её корректно инициализировать/финализировать.
Т.е. в локальной переменной sObj.s при входе в область видимости будет мусор. При попытке присвоить ей что-нибудь компилятор попытается "освободить" старую "строку", со всеми печальными вытекающими.
В глобальной будет nil, поэтому обойдётся без AV. Но корректно освободить память компилятор не сможет. Потому как информация о managed-типах у объектов и классов хранится только для текущего уровня иерархии, но если по классу легко получить его предка, то как это сделать для объекта - даже матёрые приКОЛисты не смогли додуматься, насколько я помню. А компилятор, в принципе, использует те же (ну или почти те же) средства.
просто так (2007-10-16 09:34:00) [6]>>AV будет с локальными переменными. С глобальными, впрочем, тоже не всё гладко - будет утечка.
AV не будет. если конечно не обращаться локальному к объекту после его выхода из зоны видимости. но это другая песня.
Поясни пожалуйста по утечке
Sapersky (2007-10-16 09:25:00) [7]AV будет с локальными переменными.
С глобальными, впрочем, тоже не всё гладко - будет утечка.
для динамически созданых рекордов/обжектов присваивание стрингов/дин.массивов := '', обязательно
Если через New/Dispose(Free), то не обязательно, во всяком случае для TFirstObj. Если через GetMem/FreeMem - то да.
просто так (2007-10-16 07:36:00) [8]>>TSecondObj ничего не знает об s : String; и не сможет её корректно инициализировать/финализировать. Хотя проблема не фатальная - например, в библиотеке KOL она решена созданием объектов через New (при этом поля заполняются нулями) и уничтожением всех строк вручную в деструкторе (s := '').
так сделано совсем не по этому. для динамически созданых рекордов/обжектов присваивание стрингов/дин.массивов := '', обязательно иначе будут мемлики. для переменных объявленных в секции var за нас это сделает компилятор
просто так (2007-10-16 07:13:00) [9]>>Sapersky
program Project1;
{$APPTYPE CONSOLE}
uses
SysUtils;
type
TFirstObj = object
s : String;
end;
TSecondObj = object (TFirstObj)
end;
Var fObj : TFirstObj;
sObj : TSecondObj;
begin
fObj.s := '1' ;// всё нормально
sObj.s := '2' ;// всё нормально
end.
Проверь еще раз
просто так (2007-10-16 07:10:00) [10]>>у меня в BDS2006 один модуль как то не хотел компилироваться, потому, что там вместо class было объявлено object.
думаю причины были совсем не в object. с ними всё ок в BDS2006.
>>sObj.s := ... ;// AV
врешь и не краснеешь)). хотя может дело в коментарии
fObj.s := ... ;// всё нормально
sObj.s := ... ;// всё нормально
так всё работает)) может ты использовал виртуальные методы до вызова конструктора?
Sapersky (2007-10-16 02:46:00) [11]с чего это вдруг ничего не знает?
В основном потому, что на момент создания object managed-типов ещё не было в природе. А потом - то ли было в принципе невозможно, то ли не захотели менять внутреннюю структуру object, чтобы не поломать обратную совместимость.
Можете проверить:
Var fObj : TFirstObj;
sObj : TSecondObj;
fObj.s := ... ;// всё нормально
sObj.s := ... ;// AV
DVM (2007-10-15 22:41:00) [12]у меня в BDS2006 один модуль как то не хотел компилироваться, потому, что там вместо class было объявлено object. Просто не компилировался и все. Писал внутренняя ошибка и курсор вставал на завершающую точку в модуле. Пришлось поменять. А в предыдущих версиях все нормально компилировалось.
просто так (2007-10-15 21:32:00) [13]>>TSecondObj ничего не знает об s : String
с чего это вдруг ничего не знает? на то оно и наследование чтоб знать))
Sapersky (2007-10-15 20:23:00) [14]Наследование в сочетании с managed-типами (aka типы с управляемым временем жизни - длинные строки, дин. массивы, варианты, интерфейсы) может привести к проблемам:
TFirstObj = object
s : String;
end;
TSecondObj = object (TFirstObj)
// ...
end;
TSecondObj ничего не знает об s : String; и не сможет её корректно инициализировать/финализировать. Хотя проблема не фатальная - например, в библиотеке KOL она решена созданием объектов через New (при этом поля заполняются нулями) и уничтожением всех строк вручную в деструкторе (s := '').
Прискорбно жаль, что Борланд/КодГир ничего не пишут в хелпе по этому поводу (кроме their use is not recommended).
М-да, только сейчас сообразил: если ваш супер-компонент выделяет память через GetMem, ему managed-типы вообще противопоказаны. Ну разве что обрабатывать их вручную в InitItem и FreeItem - но какие они после этого managed.
Anatoly Podgoretsky (2007-10-15 14:10:00) [15]
> а вот это наврятли
А вот это запросто, Борланд предупреждал.
просто так (2007-10-15 13:16:00) [16]>>Работает нормально
Пока у обжекта нет виртуальных методов он не отличается от рЕкорда
>>object нельзя потому, что их поддержка в следующих версиях отсутствует?
а вот это наврятли
Leonid Troyanovsky (2007-10-13 15:41:00) [17]
> Key (13.10.07 09:56)
> Работает нормально, но после работы с классами очень неуютно
> чувствуешь себя с record. Ни тебе метод написать, ни свойство.
> Появилась идея заменить record на .... "устаревший" object.
Напиши лучше свой компонент для управления чужим.
Например, ссылки на распределенные записи будет
держать TList и т.д.
Не забудь про Notification; override для того, чтобы
всегда иметь валидную ссылку на чужой.
--
Regards, LVT.