Delphi 动态数组变量重用
Delphi dynamic array variable reuse
我最近在 Delphi 中发现了一个关于动态数组的有趣“陷阱”,想知道避免该问题的最佳方法。
假设我们有以下示例,其中重复使用了动态数组变量:
function FillArray(Count: Integer): TArray<Integer>;
var
i: Integer;
begin
SetLength(result, Count);
for i := 0 to Count - 1 do
result[i] := i;
end;
procedure TfrmMain.Button1Click(Sender: TObject);
var
list: TArray<Integer>;
begin
list := FillArray(5);
meLog.Lines.Add(IntToStr(NativeInt(list)));
list := FillArray(8);
meLog.Lines.Add(IntToStr(NativeInt(list)));
list := FillArray(12);
meLog.Lines.Add(IntToStr(NativeInt(list)));
end;
作为一个函数的 result
变量只是一个隐含的 var
参数,list
变量被重用并且随着数组的后续大小增加,从 5 到 8 和然后到 12,然后数组被重新分配,因此输出是:
2138845992
2138930232
2138887416
但是如果我先从 12 大小开始创建:
list := FillArray(12);
meLog.Lines.Add(IntToStr(NativeInt(list)));
list := FillArray(8);
meLog.Lines.Add(IntToStr(NativeInt(list)));
list := FillArray(5);
meLog.Lines.Add(IntToStr(NativeInt(list)));
然后重复使用相同的动态数组,因为不需要重新分配,输出是:
2138887416
2138887416
2138887416
这是一个令人讨厌的“陷阱”,就好像我将 list
的每个赋值存储在其他地方然后我没有得到唯一的数组。
这很容易避免,我可以这样做:
function FillArray(Count: Integer): TArray<Integer>;
var
i: Integer;
begin
result := nil;
SetLength(result, Count);
for i := 0 to Count - 1 do
result[i] := i;
end;
或
list := nil;
list := FillArray(12);
meLog.Lines.Add(IntToStr(NativeInt(list)));
list := nil;
list := FillArray(8);
meLog.Lines.Add(IntToStr(NativeInt(list)));
list := nil;
list := FillArray(5);
meLog.Lines.Add(IntToStr(NativeInt(list)));
或
list := Copy(FillArray(12));
meLog.Lines.Add(IntToStr(NativeInt(list)));
list := Copy(FillArray(8));
meLog.Lines.Add(IntToStr(NativeInt(list)));
list := Copy(FillArray(5));
meLog.Lines.Add(IntToStr(NativeInt(list)));
其中任何一个都会给我一个独特的数组。最好的似乎是 result := nil
,因为您会假设这样的函数应该 return 是一个唯一的数组。但是设置 result := nil
,然后做 setLength
看起来是错误的,不理解这个问题的人可能会在将来删除 result := nil
,认为它是多余的。
所以我的问题是,我的理解是否正确,是否有更好的方法来创建唯一的动态数组?
“如果我将列表的每个分配存储在其他地方,那么我就不会得到唯一的数组。”
如果您复制每个列表,则该列表不会重用,因为动态数组是reference-counted.
运行 使用此代码再次测试:
procedure TfrmMain.Button1Click(Sender: TObject);
var
list,
list1,
list2: TArray<Integer>;
begin
list := FillArray(12);
meLog.Lines.Add(IntToStr(NativeInt(list)));
list1 := list;
list := FillArray(8);
meLog.Lines.Add(IntToStr(NativeInt(list)));
list2 := list;
list := FillArray(5);
meLog.Lines.Add(IntToStr(NativeInt(list)));
end;
日志每次都会显示不同的值。
我最近在 Delphi 中发现了一个关于动态数组的有趣“陷阱”,想知道避免该问题的最佳方法。
假设我们有以下示例,其中重复使用了动态数组变量:
function FillArray(Count: Integer): TArray<Integer>;
var
i: Integer;
begin
SetLength(result, Count);
for i := 0 to Count - 1 do
result[i] := i;
end;
procedure TfrmMain.Button1Click(Sender: TObject);
var
list: TArray<Integer>;
begin
list := FillArray(5);
meLog.Lines.Add(IntToStr(NativeInt(list)));
list := FillArray(8);
meLog.Lines.Add(IntToStr(NativeInt(list)));
list := FillArray(12);
meLog.Lines.Add(IntToStr(NativeInt(list)));
end;
作为一个函数的 result
变量只是一个隐含的 var
参数,list
变量被重用并且随着数组的后续大小增加,从 5 到 8 和然后到 12,然后数组被重新分配,因此输出是:
2138845992
2138930232
2138887416
但是如果我先从 12 大小开始创建:
list := FillArray(12);
meLog.Lines.Add(IntToStr(NativeInt(list)));
list := FillArray(8);
meLog.Lines.Add(IntToStr(NativeInt(list)));
list := FillArray(5);
meLog.Lines.Add(IntToStr(NativeInt(list)));
然后重复使用相同的动态数组,因为不需要重新分配,输出是:
2138887416
2138887416
2138887416
这是一个令人讨厌的“陷阱”,就好像我将 list
的每个赋值存储在其他地方然后我没有得到唯一的数组。
这很容易避免,我可以这样做:
function FillArray(Count: Integer): TArray<Integer>;
var
i: Integer;
begin
result := nil;
SetLength(result, Count);
for i := 0 to Count - 1 do
result[i] := i;
end;
或
list := nil;
list := FillArray(12);
meLog.Lines.Add(IntToStr(NativeInt(list)));
list := nil;
list := FillArray(8);
meLog.Lines.Add(IntToStr(NativeInt(list)));
list := nil;
list := FillArray(5);
meLog.Lines.Add(IntToStr(NativeInt(list)));
或
list := Copy(FillArray(12));
meLog.Lines.Add(IntToStr(NativeInt(list)));
list := Copy(FillArray(8));
meLog.Lines.Add(IntToStr(NativeInt(list)));
list := Copy(FillArray(5));
meLog.Lines.Add(IntToStr(NativeInt(list)));
其中任何一个都会给我一个独特的数组。最好的似乎是 result := nil
,因为您会假设这样的函数应该 return 是一个唯一的数组。但是设置 result := nil
,然后做 setLength
看起来是错误的,不理解这个问题的人可能会在将来删除 result := nil
,认为它是多余的。
所以我的问题是,我的理解是否正确,是否有更好的方法来创建唯一的动态数组?
“如果我将列表的每个分配存储在其他地方,那么我就不会得到唯一的数组。”
如果您复制每个列表,则该列表不会重用,因为动态数组是reference-counted.
运行 使用此代码再次测试:
procedure TfrmMain.Button1Click(Sender: TObject);
var
list,
list1,
list2: TArray<Integer>;
begin
list := FillArray(12);
meLog.Lines.Add(IntToStr(NativeInt(list)));
list1 := list;
list := FillArray(8);
meLog.Lines.Add(IntToStr(NativeInt(list)));
list2 := list;
list := FillArray(5);
meLog.Lines.Add(IntToStr(NativeInt(list)));
end;
日志每次都会显示不同的值。