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

Вниз

Как работает знак := для рекордов?   Найти похожие ветки 

 
yantux ©   (2009-12-19 14:41) [0]

Правильно ли я понимаю, что если переменные a и b типа рекорд, то при a:=b; копируются значения всех полей b в a?


unit Unit1;

interface

uses
 Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
 Dialogs, StdCtrls;

type

 type1 = record
   i : integer;
   f : extended;
 end;

 type2 = record
   field : type1;
 end;

 TForm1 = class(TForm)
   Memo1: TMemo;
   Button1: TButton;
   Button2: TButton;
   Button3: TButton;
   procedure Button3Click(Sender: TObject);
   procedure Button2Click(Sender: TObject);
   procedure Button1Click(Sender: TObject);
 private
   { Private declarations }
 public
   { Public declarations }
 end;

 const
   LF1 = #13;
   LF2 = #10;

var
 Form1: TForm1;
 t11, t12 : type1;
 t21, t22 : type2;

implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
begin
 t11.i:=123;
 t11.f:=456.789;
 t12.i:=11;
 t12.f:=22.33;
 self.Memo1.Lines.Add("1: t11: i="+inttostr(t11.i)+" f="+floattostr(t11.f)+LF1+LF2);
 self.Memo1.Lines.Add("2: t12: i="+inttostr(t12.i)+" f="+floattostr(t12.f)+LF1+LF2);
 t12:=t11;
 self.Memo1.Lines.Add("3: t11: i="+inttostr(t11.i)+" f="+floattostr(t11.f)+LF1+LF2);
 self.Memo1.Lines.Add("4: t12: i="+inttostr(t12.i)+" f="+floattostr(t12.f)+LF1+LF2);

end;

procedure TForm1.Button2Click(Sender: TObject);
begin
 self.Memo1.Lines.Clear;
end;

procedure TForm1.Button3Click(Sender: TObject);
begin
 t21.field.i:=123;
 t21.field.f:=456.789;
 t22.field.i:=11;
 t22.field.f:=22.33;
 self.Memo1.Lines.Add("1: t21: i="+inttostr(t21.field.i)+" f="+floattostr(t21.field.f)+LF1+LF2);
 self.Memo1.Lines.Add("2: t22: i="+inttostr(t22.field.i)+" f="+floattostr(t22.field.f)+LF1+LF2);
 t22:=t21;
 self.Memo1.Lines.Add("3: t21: i="+inttostr(t21.field.i)+" f="+floattostr(t21.field.f)+LF1+LF2);
 self.Memo1.Lines.Add("4: t22: i="+inttostr(t22.field.i)+" f="+floattostr(t22.field.f)+LF1+LF2);

end;

end.


 
Sapersky   (2009-12-19 15:03) [1]

Для записей с managed-полями (строки и т.п.) вызывается system._CopyRecord, которая корректно их копирует (с увеличением RefCount). Для простых - побайтное копирование, не очень хорошо помню, но вроде бы оно инлайнится, для мелких записей последовательность mov, для больших movsd/movsb.
Вообще такие вещи проверяются элементарно - ставьте брейк на копировании и жмите Ctrl-Alt-C.


 
Омлет ©   (2009-12-19 15:04) [2]

Правильно.


 
yantux ©   (2009-12-21 11:31) [3]


> Для записей с managed-полями (строки и т.п.) вызывается
> system._CopyRecord, которая корректно их копирует (с увеличением
> RefCount). Для простых - побайтное копирование, не очень
> хорошо помню, но вроде бы оно инлайнится, для мелких записей
> последовательность mov, для больших movsd/movsb.Вообще такие
> вещи проверяются элементарно - ставьте брейк на копировании
> и жмите Ctrl-Alt-C.


что такое ref count?


 
Sapersky   (2009-12-21 13:15) [4]

Счётчик ссылок, используется для автоматического уничтожения длинных строк, дин. массивов и пр. типов с управляемым временем жизни.
http://www.rsdn.ru/article/Delphi/dynarrays.xml


 
yantux ©   (2009-12-21 15:55) [5]


> Счётчик ссылок, используется для автоматического уничтожения
> длинных строк, дин. массивов и пр. типов с управляемым временем
> жизни.


А зачем увеличиние RefCount, если по знаку := должно происходить копирование данных, а не ссылок на данные?


 
RWolf ©   (2009-12-21 16:19) [6]

очевидно, строки не копируются.


 
yantux ©   (2009-12-21 17:12) [7]


> очевидно, строки не копируются.


т.е. тип string?

type

d = record
i : integer;
s : string;
end;

var
a, b  : d;

begin
a:=b;
end.

В этом примере значение всех полей переменной b будen нормально будут нормально скопированы в переменную a, т.е. именно значения, а не ссылки на них. Тогда почему будет увеличиваться RefCount?


 
Ega23 ©   (2009-12-21 17:15) [8]

потому что string - это не совсем простой тип данных.


 
RWolf ©   (2009-12-21 17:43) [9]


> RWolf ©   (21.12.09 16:19) [6]
> очевидно, строки не копируются.

Всё не так очевидно, вообще говоря. Попробуем посмотреть содержимое этих записей до и после копирования:
procedure TForm1.Button1Click(Sender: TObject);
type
 d = record
   i : integer;
   s : string;
 end;

var
 a, b  : d;

 function getaddr(const dd:d):string;
 var p:^Cardinal;pc:PChar;
 begin
   p:=@dd;
   Inc(p); //указывает на dd.s
   Result:=IntToHex(p^,8);
   p:=Pointer(p^); //указывает на собственно символы строки
   pc:=PChar(p);
   Result:=Result+" "+pc;
 end;

begin
 a.s:="asfdsadf";
 b.s:="qweqwe";
 ShowMessage(getaddr(a)+#13#10+getaddr(b));
 a:=b;
 ShowMessage(getaddr(a)+#13#10+getaddr(b));
end;


вот что получаем в результате:

до копирования a:=b
00452B7C asfdsadf
00452B90 qweqwe

после копирования a:=b
00953BD4 qweqwe
00452B90 qweqwe


т.е. имеем две копии строки в памяти.


 
Sapersky   (2009-12-21 18:53) [10]

Это связано со специфической обработкой строковых констант. Если сделать так:
a.s := InttoStr(123); b.s := InttoStr(456);
то значения указателей будут равны.
Здесь должно быть расписано:
http://www.delphikingdom.com/asp/viewitem.asp?catalogid=1206


 
Leonid Troyanovsky ©   (2009-12-21 18:56) [11]


> RWolf ©   (21.12.09 17:43) [9]


> т.е. имеем две копии строки в памяти.

Не очень понятно, что, собс-но, исследуется.
Вот, например, количество ссылок:

type

d = record
i : integer;
s : string;
end;

type
 PStrRec = ^StrRec;
 StrRec = packed record
   refCnt: Longint;
   length: Longint;
 end;

var
a, b  : d;

procedure TForm1.Button1Click(Sender: TObject);
begin
 a.i := GetTickCount;
 a.s := IntToStr(a.i);
 b := a;
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
 Caption := IntToStr(PStrRec(PChar(a.s)-SizeOf(StrRec)).RefCnt);
end;

А убедиться, что b.s не копируется (а ссылается на a.s)
можно сравнив их адреса: Pointer(a.s) vs Pointer(b.s).
Т.е., имеем обычное copy-on-write .

--
Regards, LVT.


 
RWolf ©   (2009-12-22 13:46) [12]


> Sapersky   (21.12.09 18:53) [10]

Полезная статья, спасибо.
По прочтении осталось неясным, по какой причине в [9] после присвоения a:=b значение указателя на константную строку b.s не копируется в a.s, вместо этого создаётся новая строка, с тем же содержимым.


 
Sapersky   (2009-12-22 14:48) [13]

Комментарий к system._LStrAsg:
 "Literals [константы] are copied to prevent a situation where a dynamically
 allocated DLL or package assigns a literal to a variable and then
 is unloaded -- thereby causing the string memory (in the code
 segment of the DLL) to be removed -- and therefore leaving the
 global variable pointing to invalid memory."


 
RWolf ©   (2009-12-22 15:39) [14]

[13]
да, пусть уж лучше создаётся копия :)



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

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

Наверх




Память: 0.51 MB
Время: 0.012 c
9-1183470560
THandle
2007-07-03 17:49
2010.02.21
DirectX


15-1260401856
Германн
2009-12-10 02:37
2010.02.21
Маленькая offtop шутка.


15-1258018282
Максимильянов
2009-11-12 12:31
2010.02.21
Работа МФУ HP LJ M1120n MFP в сети


15-1255067207
MBo
2009-10-09 09:46
2010.02.21
Пятничные задачки. Вася Пупкин и компания...


2-1261250556
POOP
2009-12-19 22:22
2010.02.21
Помогите, пожалуйста с префиксной формой...