동적 배열 필드가있는 advanced record
이 있습니다. 레코드는 레코드와 바이트의 연결을 위해 class operator
입니다. 또한 바이트를 추가하는 Add 메서드입니다.레코드의 동적 배열 참조 횟수
레코드를 사용하려면 동적 배열 필드의 참조 횟수가 중요합니다. 아래의 두 시험 절차를 실행하면 볼 수 있습니다 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.
컴파일러의 참조 카운트에 추가 방법의 결과는 별도의 참조 카운트 때을 담당하면서 2의 참조 카운트에 연결 결과 레코드 변수는 범위를 벗어나므로이 시점에서 실제로 아무런 문제가 없습니다.
하지만이 동작을 설명 할 수 있습니까? 문서화되지 않은 구현 세부 사항입니까? 추가 카운트를 피할 수있는 방법이 있습니까?
문서화되지 않은 구현 세부 사항에 대해 말하자면 동적 배열의 참조 카운트에 의존하여 처음부터 특정 값을 갖게되는 것이 취성 설계처럼 보입니다. –
@RobKennedy, 무슨 뜻인지 잘 모르겠지만 왜 동적 배열의 참조 카운트를 신뢰하지 않겠습니까? 문자열과 마찬가지로 개수가 0이되면 힙에서 자체를 제거합니다. –
물론, 그것이 0 일 때 누가 말합니까? 이 설명서에는 참조 횟수가 언제 변경되는지에 대한 철저한 목록이 없습니다. 참조 횟수가 1 일 때만, 0으로 변경되면 어떻게되는지 알려줍니다. 그것은 * 언제 * 그것이 0으로 변한다고 말하지 않습니다. –