2015-06-28 49 views
-1

我需要一个数组,它在运行时对一次性初始化进行了优化,并具有给定的长度。所以内存应该在运行时分配,但我不需要改变它的长度。如何在delphi中声明一个可变长度的静态数组?

是否存在除纯动态数组之外的数组类型? (这似乎是无法完成这个任务的最佳选择)

奖金会是这样,如果初始化数组是通过指针迭代可转位,所以它的所有元素被分配在内存中连续的。

这是一个非经验的程序员的一切只是一个白日梦,或者是有可能实现这一目标?

我能想象与手动内存分配要做到这一点,但也许有另一种方式。

编辑:

我主要关注的是阵列的读写速度。

+0

不,没有。它不再是静态的。 – TLama

+1

那么究竟是什么阻止我在运行时初始化静态数组?在编译的硬编码内存块和运行时生成的“保证内存块”数组之间有什么不同? – Art1st

+1

@ Art1st如果初始化(包括分配)发生在您自己的代码中,那必然意味着在可以运行的初始化之前可能存在代码*。 (例如,如果您有两个这样的数组,则一个初始化必须在另一个之前执行。)如果其他代码访问尚未初始化的数组,则会发生什么情况?无论你的答案是什么,这是否意味着数组更像静态数组,或更像是一个动态数组? (我强烈怀疑后者。) – hvd

回答

2

你可以在通用类型中封装你想要的东西。就像这样:

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]); 

Access项目中是这样的:

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

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

有一点要注意这里是该类型将像一个引用类型,因为它的数据存储在引用类型。也就是说,这种类型的赋值运算符的行为方式与动态数组赋值相同。

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

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

如果你想使型表现得像一个真正的价值,那么你会实现写入时复制里面有SetItem

更新

你编辑的问题变化显著的。事实上,你似乎更关心性能而不是封装。

在上述类型的项的存取方法的内联意味着性能特性应接近阵列。访问仍然是O(1),但内联/优化器很弱并且无法发出最优代码是非常合理的。

在你决定,你必须使用数组,以获得绝对极致的表现,做一些真实世界的标杆。在我看来,从阵列读取/写入的代码确实是一个瓶颈的可能性非常小。最有可能的瓶颈将是你对数组中的值做什么。

+0

与仅使用TArray 相比,是否有这种速度优势,或者这只是为了防止程序员在运行时改变其长度? – Art1st

+0

不可能是速度差异。如果内衬拧紧,它会变慢。阅读时间可能会更快,但我怀疑它。重点是停止编程改变长度,这正是我所理解的你所要求的。 –

+0

我这个问题的主要原因确实是速度问题,我希望有一种确保紧凑内存的类型,所以我可以正好访问O(1)中的任何数组项,但无论如何,这个答案给出了我的解决方案第二个问题,初始化后改变长度。 – Art1st

3

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

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

对于更低级的东西,具有更多功能(如JSON或二进制序列化,或通过一个或多个属性的散列进行快速查找),您可以查看我们的TDynArray dynamic array wrapper。这些只是现有动态数组的封装,而不是像TList<T>这样的数据保存器。他们从德尔福5或更老的工作,也是FPC。

相关问题