Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Основная";
Текущий архив: 2006.10.15;
Скачать: [xml.tar.bz2];

Вниз

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

 
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;
Скачать: [xml.tar.bz2];

Наверх




Память: 0.54 MB
Время: 0.045 c
15-1158941601
McSimm
2006-09-22 20:13
2006.10.15
Обновлённая документация на FastReport


2-1159467945
Ezorcist
2006-09-28 22:25
2006.10.15
Выдернуть подструку из строки


15-1158922625
matt
2006-09-22 14:57
2006.10.15
Не правильная рессора?


2-1159201684
Mishenka
2006-09-25 20:28
2006.10.15
Как распечатать StringGrid?


15-1159089578
PHPDeveloper
2006-09-24 13:19
2006.10.15
An error has occurred in the scriptm on this page





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