У меня есть advanced record
с динамическим полем массива. В записи есть class operator
для конкатенации записи и байт. Также добавьте метод, добавив байт.Счетчик динамического массива в записи
Для того, что я собираюсь использовать запись, значение ссылки на поле динамического массива имеет важное значение. При выполнении этих двух процедур испытаний ниже, вы можете увидеть, что результаты конкатенации в счетчик ссылок 2, а результаты метода добавить в счетчик ссылок 1.
program TestReferenceCount;
{$APPTYPE CONSOLE}
uses
System.SysUtils;
Type
TRec = record
class operator Add(const a: TRec; b: Byte): TRec;
private type
PDynArrayRec = ^TDynArrayRec;
TDynArrayRec = packed record
{$IFDEF CPUX64}
_Padding: LongInt; // Make 16 byte align for payload..
{$ENDIF}
RefCnt: LongInt;
Length: NativeInt;
end;
private
FArr: TBytes;
function GetRefCnt: Integer;
public
procedure Add(b : Byte);
property RefCnt: Integer read GetRefCnt;
end;
procedure TRec.Add(b : Byte);
var
prevLen: Integer;
begin
prevLen := System.Length(Self.FArr);
SetLength(Self.FArr, prevLen + 1);
Self.FArr[prevLen] := b;
end;
class operator TRec.Add(const a: TRec; b: Byte): TRec;
var
aLen: Integer;
begin
aLen := System.Length(a.FArr);
SetLength(Result.FArr, aLen + 1);
System.Move(a.FArr[0], Result.FArr[0], aLen);
Result.FArr[aLen] := b;
end;
function TRec.GetRefCnt: Integer;
begin
if Assigned(FArr) then
Result := PDynArrayRec(NativeInt(FArr) - SizeOf(TDynArrayRec)).RefCnt
else
Result := 0;
end;
procedure TestConcatenation;
var
r1 : TRec;
begin
WriteLn('RC:', r1.RefCnt); // <-- Writes 0
r1 := r1 + 65;
WriteLn('RC:', r1.RefCnt); // <-- Writes 2
end;
procedure TestAdd;
var
r1 : TRec;
begin
WriteLn('RC:', r1.RefCnt); // <-- Writes 0
r1.Add(65);
WriteLn('RC:', r1.RefCnt); // <-- Writes 1
end;
begin
TestConcatenation;
TestAdd;
ReadLn;
end.
компилятор берет на себя дополнительный счетчик ссылок когда это переменная записи выходит за рамки, поэтому на данный момент нет проблем.
Но можно ли объяснить это поведение? Это недокументированная деталь реализации? Есть ли способ избежать лишнего счета?
Говоря о недокументированных деталях реализации, полагаясь на подсчет ссылок динамического массива, чтобы иметь какое-то особое значение, в первую очередь, кажется хрупким. –
@RobKennedy, не уверен, что вы имеете в виду, почему бы вам не доверять счету ссылок динамического массива? Как строка, он удалит себя из кучи, когда счетчик достигнет нуля. –
Конечно, но кто говорит, когда он будет равен нулю? В документации не приводится исчерпывающий список случаев, когда счетчик ссылок будет изменен. Он говорит только, когда счетчик ссылок будет равен 1, и что произойдет, когда он изменится на ноль. Он никогда не говорит *, когда * он меняется на ноль. –