Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

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


Страницы:   1 2

atruhin ©   (2006-09-03 12:26:00) 

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


Джо   (2006-09-03 23:47:00) [21]

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

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.


default   (2006-09-03 18:32:00) [22]

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


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

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


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


default   (2006-09-03 18:16:00) [24]

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


sniknik   (2006-09-03 14:59:00) [25]

> аА у 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", но это частности ткак сказать, зачем автору это нужно неясно, может как раз таких/похожих "замоморочек" хочет избежать... а тут, это. ;о)


atruhin   (2006-09-03 14:54:00) [26]

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

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


Джо   (2006-09-03 14:02:00) [27]

> [3] Palladin ©  

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


Palladin   (2006-09-03 13:46:00) [28]

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


Джо   (2006-09-03 13:35:00) [29]

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

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


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

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

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

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


Страницы:   1 2

Наверх

Титульная страница Поиск, карта сайта Написать письмо