如何在delphi中声明一个可变长度的静态数组?

时间:2015-06-28 10:22:38

标签: arrays delphi

我需要一个数组,它针对运行时的一次性初始化进行了优化,具有给定的长度。所以内存应该在运行时分配,但我不需要改变它的长度。

是否有纯动态数组以外的数组类型? (它似乎不是这项任务的最佳选择)

如果初始化的数组可以通过指针迭代进行索引,那么奖励就是,所以它的所有元素都在内存中连续分配。

这只是一个没有经验的程序员的白日梦,还是有可能实现这一目标?

我可以想象用手动内存分配来做到这一点,但也许还有另一种方式。

修改

我主要担心的是数组的读写速度。

2 个答案:

答案 0 :(得分:4)

只需使用外部Count: integer变量,并使用动态数组长度作为数组的“容量”。如果数组的初始容量定义良好,它将避免大多数内存分配。

实际上,TList<T>单元中定义的System.Generics.Collections正在使用此方案:它在内部存储一个数组,但它有自己的Count属性。我怀疑这就是你要找的东西。

对于更低级别的东西,具有更多功能(如JSON或二进制序列化,或通过一个或多个属性的散列快速查找),您可以查看我们的TDynArray dynamic array wrapper。这些只是现有动态数组的包装器,而不是像TList<T>这样的数据持有者。它们使用的是Delphi 5或更早版本,也适用于FPC。

答案 1 :(得分:3)

您可以在通用类型中封装您想要的内容。像这样:

type
  TFixedLengthArray<T> = record
  strict private
    FItems: TArray<T>;
    FLength: Integer;
    function GetItem(Index: Integer): T; inline;
    procedure SetItem(Index: Integer; const Value: T); inline;
  public
    property Length: Integer read FLength;
    property Items[Index: Integer]: T read GetItem write SetItem; default;
    class function New(const Values: array of T): TFixedLengthArray<T>; static;
  end;

{ TFixedLengthArray<T> }

class function TFixedLengthArray<T>.New(const Values: array of T): TFixedLengthArray<T>;
var
  i: Integer;
begin
  Result.FLength := System.Length(Values);
  SetLength(Result.FItems, Result.FLength);
  for i := 0 to Result.FLength-1 do begin
    Result.FItems[i] := Values[i];
  end;
end;

function TFixedLengthArray<T>.GetItem(Index: Integer): T;
begin
  Result := FItems[Index];
end;

procedure TFixedLengthArray<T>.SetItem(Index: Integer; const Value: T);
begin
  FItems[Index] := Value;
end;

像这样创建一个新的:

var
  MyArray: TFixedLengthArray<Integer>;
....
MyArray: TFixedLengthArray<Integer>.New([1, 42, 666]);

访问以下内容:

for i := 0 to MyArray.Length-1 do
  Writeln(MyArray[i]);

这只是包装一个动态数组。元素是连续的。一次确定数组的长度,然后创建一个新实例。

这里需要注意的一点是,类型的行为类似于引用类型,因为它的数据存储在引用类型中。也就是说,此类型的赋值运算符的行为方式与动态数组赋值的行为方式相同。

因此,如果我们有两个此类型的变量arr1arr2,则会发生以下情况:

arr1 := arr2;
arr1[0] := 42;
Assert(arr2[0] = 42);

如果你想让类型表现得像真值那么你就可以在SetItem内实现copy-on-write。

<强>更新

您对问题更改的编辑非常重要。事实上,你似乎更关注性能而不是封装。

上述类型中项目访问器方法的内联意味着性能特征应该接近于数组的性能特征。访问仍然是O(1),但是内联器/优化器很弱并且无法发出最佳代码是非常合理的。

在您决定必须使用数组来获得绝对最终性能之前,请先进行一些真实的基准测试。在我看来,从数组读取/写入的代码确实是一个瓶颈。很可能瓶颈将是你对数组中的值所做的事情。