Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2006.10.15;
Скачать: CL | DM;

Вниз

Ипользование объекта вместо записи   Найти похожие ветки 

 
atruhin ©   (2006-09-03 12:26) [0]

Иногда удобно вместо записи использовать объект, например:
Вместо:
record X,Y : integer; end;
Использовать:
class
 X, Y : integer;
 constructor Create(aX,aY : integer);
end;
Вопрос: какова разница в объеме занимаемой памяти? Т.е. таблицы VMT, доп. информация? И влияет ли на разницу наличие constructor


 
Юрий Зотов ©   (2006-09-03 12:59) [1]

Сам объект занимает на 4 байта больше аналогичной записи (по нулеврму смещению он содержит неявное поле - ссылку на VMT). Плюс хотя бы одна ссылка на этот объект (он же не может, как запись, располагаться в статической памяти) - еще 4 байта. Размер VMT для разных версий Delphi тоже немного разный, но где-то примерно около сотни байт (конкретно можно посмотреть в System.pas). Плюс таблица полей, таблица свойств, таблица методов... их размер зависит от количества этих самых полей, свойств и методов в секции published (если компиляция идет с $M+). В общем, минимальная разница - примерно байт сто, но может быть и больше.

Влияет ли на разницу наличие constructor - если этот конструктор имеет код, то где-то этот код тоже ведь должен храниться? Он и хранится, в теле самой программы. Плюс небольшие накладные расходы на код вызова конструктора и деструктора.

ИМХО, можно просто создать процедуру типа CreateMyRecord - и тогда овчинка вряд ли стоит выделки.


 
Джо ©   (2006-09-03 13:35) [2]

> ИМХО, можно просто создать процедуру типа CreateMyRecord
> - и тогда овчинка вряд ли стоит выделки.

Или использовать компилятор BDS 2006 с новым синтаксисом записей, в котором позволены методы в записях.


 
Palladin ©   (2006-09-03 13:46) [3]

Или использовать, чуть более широкий по возможностям чем Record, Object. В котором позволены методы со времен TP5.5 :)


 
Джо ©   (2006-09-03 14:02) [4]

> [3] Palladin ©  

А у object накладные расходы на служебную информацию (VMT), а именно их и хотят, по возможности, избежать ;)


 
atruhin ©   (2006-09-03 14:54) [5]

> Размер VMT для разных версий Delphi тоже немного разный,
> но где-то примерно около сотни байт

Да но ведь VMT хранится для класса а не для экземпляра объекта? Тогда это не принципиально.
А вопрос вообще возникает в случае хранения тысяч объектов в памяти, например в TList и т.д., в таких случаях удобнее работать с объектами, а не записями. Т.е. насколько я понял для экземпляра объекта добавляется всего 4 байта, по сравнению с записью?


 
sniknik ©   (2006-09-03 14:59) [6]

> аА у object накладные расходы на служебную информацию (VMT), а именно их и хотят, по возможности, избежать ;)

не очень красиво, но ... пример в D7

type
 TMet = record
   x, y: integer;
   Show: TNotifyEvent;
 end;
 PMet = ^TMet;

 TForm1 = class(TForm)
   Button1: TButton;
   procedure FormCreate(Sender: TObject);
   procedure Button1Click(Sender: TObject);
 private
   Met: TMet;
   procedure MetShow(Sender: TObject);
 public
 end;

var
 Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.MetShow(Sender: TObject);
var
 LocMet: PMet;
begin
 LocMet:= PMet(Pointer(Self));
 ShowMessage(IntToStr(LocMet.x + LocMet.y));
end;

procedure TForm1.FormCreate(Sender: TObject);

 procedure SetMethod(val: TNotifyEvent);
 begin
   TMethod(Met.Show).Code:= TMethod(val).Code;
   TMethod(Met.Show).Data:= @Met;
 end;

begin
 SetMethod(MetShow);
 Met.x:= 10;
 Met.y:= 15;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
 Met.Show(Self);
end;


и удобным это тоже не назовеш... но накладные расходы на VMT избегаются.
ну еще лучше бы вынести всю обработку рекорда в отдельный модуль, тогда чтобы не привязыватся к форме обработчики делать процедурами "of object", но это частности ткак сказать, зачем автору это нужно неясно, может как раз таких/похожих "замоморочек" хочет избежать... а тут, это. ;о)


 
default ©   (2006-09-03 18:16) [7]

цель замена какая?


 
tesseract ©   (2006-09-03 18:23) [8]

> [4] Джо ©   (03.09.06 14:02)


Ну и плюс с приведением типов проблемы будут. Лучше уж запись.


 
default ©   (2006-09-03 18:32) [9]

цель, как я понимаю, недопустить использование неинициализированных данных
хорошая цель
например, CLR дотнетовская воспринимает обращение к неинициализированных данным(обычно они находятся в стеке) как код не проходящий верификацию:) то есть в безопасной среде - такой код исполнен не будет
так что шаги на пути к безопасному коду я только поощряю:)


 
Джо ©   (2006-09-03 23:47) [10]

Я как-то для хранения большого количества однотипных объектов использовал (для уменьшения расходов памяти) следующий подход. Внутренне данные хранились в приватном поле класса в динамическом массиве. А наружу торчал аксессор, на лету преобразующий элементы массива в класс, точнее, интерфейс.
Вот упрощенный и несколько схематичный пример, основанный на реальном коде. :) Кажется, есть какой-то "паттерн" такой, забыл только название.

unit Points;

interface
uses SysUtils;

type

 IPoint = interface
   ["{245732B1-B9AF-415D-9269-8DC9ACA8A1D3}"]
   function GetX: Double;
   function GetY: Double;
   procedure SetX (const Value: Double);
   procedure SetY (const Value: Double);
   property X: Double read GetX write SetX;
   property Y: Double read GetY write SetY;
   // ...
   // ...
 end;

 TPoints = class; // forward declaration

 TPoint = record
   X,Y: Double;
 end;

 TPointArray = array of TPoint;

 TPoints = class
 private
   FPointArray: TPointArray; // Массив записей, а не классов!
   function GetPoints(Index: Integer): IPoint;
   procedure SetPoints(Index: Integer; const Value: IPoint);
 public
   property Points[Index: Integer]: IPoint read GetPoints write SetPoints; default;
   function AddPoint (const X,Y: Double): Integer;
   // ...
   // ...
 end;

implementation

type

 TPointClass = class (TInterfacedObject, IPoint)
 private
   FParent: TPoints;
   FParentIndex: Integer;
   FX,
   FY: Double;
   function GetX: Double;
   function GetY: Double;
   procedure SetX (const Value: Double);
   procedure SetY (const Value: Double);
   procedure NotifyParent;
 public
   constructor Create (AParent: TPoints; const FParentIndex: Integer;
     const X,Y: Double);
 end;

constructor TPointClass.Create(AParent: TPoints; const FParentIndex: Integer;
 const X,Y: Double);
begin
 inherited Create;

 FX := X;
 FY := Y;
 FParent := AParent;
end;

function TPointClass.GetX: Double;
begin
 Result := FX
end;

function TPointClass.GetY: Double;
begin
 Result := FY
end;

procedure TPointClass.NotifyParent;
begin
 if Assigned(FParent) then
   FParent[FParentIndex] := Self
end;

procedure TPointClass.SetX(const Value: Double);
begin
 FX := Value;
 NotifyParent
end;

procedure TPointClass.SetY(const Value: Double);
begin
 FY := Value;
 NotifyParent
end;

function TPoints.AddPoint(const X, Y: Double): Integer;
begin
 Inc (FCount);
 if FCount > FCapacity then
   Reallocate;
   
 FPointArray[FCount-1].X := X;
 FPointArray[FCount-1].Y := Y;
 Result := FCount-1;
end;

// "На лету" преобразует элементы внутреннего массива
// в интерфейс
function TPoints.GetPoints(Index: Integer): IPoint;
begin
 Result := TPointClass.Create(Self, Index,
   FPointArray[Index].X,FPointArray[Index].Y);
end;

procedure TPoints.SetPoints(Index: Integer; const Value: IPoint);
begin
 FPointArray[Index].X := Value.X;
 FPointArray[Index].Y := Value.Y;
end;

end.


 
Германн ©   (2006-09-04 00:47) [11]

Я лично, очень часто использую объект вместо записи. Во-первых, как уже было сказано, поля объекта инициализируются при создании, во-вторых удобно создавать и использовать список таких объектов с помощью TList. Особенно с учётом Д4. Ну а размер меня мало волнует. У меня объекты создаются не очень часто и уничтожаются "как только, так сразу".


 
GrayFace ©   (2006-09-04 11:07) [12]

> Джо ©   (03.09.06 14:02) [4]
А у object накладные расходы на служебную информацию (VMT), а именно их и хотят, по возможности, избежать ;)
По-моему, расходы есть только если есть виртуальные методы.


 
atruhin ©   (2006-09-04 11:47) [13]

Спасибо за ответы. Не уверен в одном моменте.
Разница в объеме памяти между объектами и записями определяется так:
размер памяти для объектов типа:
TTest = class
 REC : TMyRecord;
end;
будет
(Sizeof(TMyRecord)+4)*CountObject + SizeOf(VMT)
где CountObject - кол-во созданных объектов.

Это правильно?


 
oxffff ©   (2006-09-04 12:15) [14]

Нет


 
atruhin ©   (2006-09-04 12:32) [15]

> [14] oxffff ©   (04.09.06 12:15)

Почему?


 
oxffff ©   (2006-09-04 12:42) [16]

taa=record
a:integer;
end;

classA=class
public
b:taa;
procedure abc;virtual;abstract;
end;

showmessage(inttostr(classA.InstanceSize)) // равно 8


 
oxffff ©   (2006-09-04 12:47) [17]

Размер объекта равен
        указатель на VMT (4 байта)
        +размер полей

Размер типа
       VMT
       +dynamic method table
       +short string containing class name
       +method definition table
       +type information table
       +instance initialization table
       +Automation information table
       +interface table


 
han_malign ©   (2006-09-04 12:52) [18]


> GrayFace ©   (04.09.06 11:07) [12]
>
> > Джо ©   (03.09.06 14:02) [4]
> >А у object накладные расходы на служебную информацию (VMT),
> > а именно их и хотят, по возможности, избежать ;)
> По-моему, расходы есть только если есть виртуальные методы.

- так и есть, причем, если добавить виртуальный метод, то адресс VMT будет лежать не по нулевому смещению, а после полей базовового объекта(из-за чего нужно быть внимательным при приведении объектных типов по record-маске)...


 
oxffff ©   (2006-09-04 12:59) [19]

> GrayFace ©   (04.09.06 11:07) [12]
>
> > Джо ©   (03.09.06 14:02) [4]
> >А у object накладные расходы на служебную информацию (VMT),
> > а именно их и хотят, по возможности, избежать ;)
> По-моему, расходы есть только если есть виртуальные методы.

han_malign
>- так и есть, причем, если добавить виртуальный метод, то адресс VMT >будет лежать не по нулевому смещению, а после полей базовового >объекта>(из-за чего нужно быть внимательным при приведении объектных >типов по record-маске)...

Вы путаете это с С++

Указатель на VMT всегда по нулевому смещению


 
oxffff ©   (2006-09-04 13:02) [20]

to han_malign
Тут возможно я не прав. Не обратил внимание на object
Прошу извинить на поспешность.


 
default ©   (2006-09-04 13:35) [21]

atruhin ©   (04.09.06 12:32) [15]
открываем справку по Delphi, затем переходим на вкладу поиска по указателю, заносим в строку поиска абру "vmt" и читаем, там всё написано
также написано и
"The first 4-byte field of every object is a pointer to the virtual method table (VMT) of the class."
надо зырить на процент памяти, используемый на указатель на vmt, по сравнению с размером записи
4/SizeOf(TRecord)
на другую инфу можно забить ибо она хранится в единственном экземпляре


 
atruhin ©   (2006-09-04 15:38) [22]

> [16] oxffff ©   (04.09.06 12:42)

Ну дак а я о чем писал? Посмотри внимательнее.

> [21] default ©   (04.09.06 13:35)

Спасибо. Исчерпывающий ответ. Больше вопросов нет.


 
oxffff ©   (2006-09-04 16:33) [23]

to atruhin
oxffff ©   (04.09.06 12:47) [16]
oxffff ©   (04.09.06 12:47) [17]
Может вам стоит быть внимательнее


 
oxffff ©   (2006-09-04 16:50) [24]

to atruhin
class это не только VMT
Размер типа
      VMT
      +dynamic method table
      +short string containing class name
      +method definition table
      +type information table
      +instance initialization table
      +Automation information table
      +interface table


 
zamtmn ©   (2006-09-05 10:16) [25]

to oxffff

> Вы путаете это с С++
>
> Указатель на VMT всегда по нулевому смещению

Справедливо для class, у object VMT не всегда находится по нулеыому смещению, более того его может не быть вообще, если нет виртуальных методов


 
zamtmn ©   (2006-09-05 10:21) [26]

tobj1=object
                field1,field2:intrger
        end;
tobj2=object(tobject1)
                field3:integer
                procedure test;virtual;abstract;
        end;
в памяти tobj1 будет выглядить - field1,field2
tobj2 - field1,field2,^VMT,field3


 
oxffff ©   (2006-09-05 10:28) [27]

to zamtmn
Полностью согласен с вами.
Когда постил
oxffff ©   (04.09.06 12:59) [19]  
не обратил внимание на object.

В следующем посте извинился.
oxffff ©   (04.09.06 13:02) [20]

Просто к счастью не довелось работать с оbject.
Вчера достал у себя в закромах старую книгу и почитал.
Действительно указатель на VMT "плавающий".


 
zamtmn ©   (2006-09-05 10:37) [28]

to oxffff
а я в свою очередь незаметил Ваш пост [20]. извиняюсь
to atruhin
в случае использования
object
X, Y : integer;
constructor Create(aX,aY : integer);
end;
разницы не будет никакой до появления виртуальных методов


 
oxffff ©   (2006-09-06 12:34) [29]

to zamtmn ©  

> разницы не будет никакой до появления виртуальных методов

Разница все таки будет.

Дело в том что для оbject все равно создается таблица VMT.
Где по -4 байт хранится смещение относительно начала экземпляра,
где хранится указатель на VMT.
Где по -8 байт хранится размер экземпляра.

Другое дело, если не объявлены виртуальные методы, тогда конструктор
просто не инициализирует в экземпляре указатель на VMT.
Но таблица VMT существовать будет.


 
zamtmn ©   (2006-09-06 13:58) [30]

>>Дело в том что для оbject все равно создается таблица VMT.
согласен, я имел ввиду разницу хранения в памяти экземпляра record и object. заголовок vmt всеравно будет создан для работы TypeOf, но он будет один для всех объектов данного типа



Страницы: 1 вся ветка

Текущий архив: 2006.10.15;
Скачать: CL | DM;

Наверх




Память: 0.56 MB
Время: 0.03 c
15-1158949396
vidiv
2006-09-22 22:23
2006.10.15
Как правильно делать свой Edit?


9-1137326026
ZeFiR
2006-01-15 14:53
2006.10.15
Таблица рекордов


2-1159611798
Piter
2006-09-30 14:23
2006.10.15
Delphi IO работает только с файлами до 2 Гб?


3-1155633565
Alpine
2006-08-15 13:19
2006.10.15
Возможно ли помещать апостроф в запись ?


2-1159195466
vyper
2006-09-25 18:44
2006.10.15
Как убить процесс