use*_*191 2 arrays delphi class
我使用数组并在类的上下文中测试了功能,例如:
Ttest = class
values : array of integer;
procedure doStuff;
end;
Run Code Online (Sandbox Code Playgroud)
与doStuff所有方法一样,这些方法都对值数组进行操作,而无需将数组作为参数传递。这适合我,而且速度很快。现在我想使用这个类来处理外部数组,比如Ttest.create(myValues)在构造函数中我可以复制myValues到内部,values但这会很浪费,而且,最后必须反转复制以将更新的值传回. 我的问题是如何扩展这个类,以便它可以有效地处理外部数组。在这样的伪代码中:
constructor create(var myValues : array of integer);
begin
address of values := address of myValues;
doSTuff;
end;
Run Code Online (Sandbox Code Playgroud)
在 Delphi 中,动态数组是引用类型。动态数组类型的变量只包含一个指向实际动态数组堆对象的指针,并且在赋值中,
A := B
Run Code Online (Sandbox Code Playgroud)
其中A和B是相同类型的动态数组,动态数组堆对象不会被复制。唯一发生的事情是A和B将指向同一个动态数组堆对象(即,将 32 位或 64 位B指针复制到A)并且堆对象的引用计数增加 1。
当你写
constructor Create(var AValues: array of Integer);
Run Code Online (Sandbox Code Playgroud)
您需要意识到,尽管外观如此,这并不是一个动态数组参数,而是一个开放的数组参数。
如果您明确需要动态数组参数,则需要明确使用这样的类型:
constructor Create(AValues: TArray<Integer>);
Run Code Online (Sandbox Code Playgroud)
根据定义,TArray<Integer> = array of Integer是Integers的动态数组。
请注意,该语言只有两种类型的数组——静态和动态;开放数组概念仅与函数参数有关。
如果您想使用动态数组,利用它们作为引用类型的性质,我建议您使用动态数组参数。然后唯一传递给函数(在这种情况下是构造函数)的是指向堆对象的指针。当然,堆对象的引用计数也会增加。
A := B
Run Code Online (Sandbox Code Playgroud)
After SetLength,Arr指向引用计数为 1 的动态数组堆对象。您可以在 RAM 中看到它(按Ctrl+ Alt+ E,然后按Ctrl+G和 goto Arr[0])。当你进入Test,引用计数增加到2,因为这两个Arr和A参考。当你离开时Test,引用计数减少回 1 因为A超出范围:现在再次只Arr引用它。
现在,一个“问题”:如果您更改动态数组的元素数量,则需要重新分配 (*)。因此,创建一个新的动态数组堆对象,引用计数为 1,旧对象的引用计数减 1(如果它变为零,则将其删除)。
因此,虽然前面的示例按预期工作,但以下示例不会:
constructor Create(var AValues: array of Integer);
Run Code Online (Sandbox Code Playgroud)
该SetLength会创建引用计数1中的新动态数组堆对象和复制旧阵列的一半到这一点,把新的地址在当地的A参数,Test将改变这一新的数组,不触及旧其中一个全局Arr变量指向。原始堆对象的引用计数减一。
但是,如果您使用var参数,
constructor Create(AValues: TArray<Integer>);
Run Code Online (Sandbox Code Playgroud)
它会像以前一样工作。这有效地与Arr. 如果我们增加了元素的数量,数组可能会被重新分配,并且全局Arr变量会被更新为新地址。
只要你不需要重新分配内存(改变元素的数量),Delphi 已经给了你你想要的,因为动态数组是引用类型。如果您确实需要重新分配,至少现在您已了解足够的技术细节以进行推理。
更新:因此,建议是这样做
var
Arr: TArray<Integer>;
procedure Test(A: TArray<Integer>);
var
i: Integer;
begin
for i := Low(A) to High(A) do
A[i] := 2*A[i];
end;
procedure TForm1.FormCreate(Sender: TObject);
var
i: Integer;
begin
SetLength(Arr, 10);
for i := 0 to High(Arr) do
Arr[i] := i;
Test(Arr);
for i := 0 to High(Arr) do
ShowMessage(Arr[i].ToString);
end;
Run Code Online (Sandbox Code Playgroud)
要测试它:
var
Arr: TArray<Integer>;
procedure Test(A: TArray<Integer>);
var
i: Integer;
begin
SetLength(A, 5);
for i := Low(A) to High(A) do
A[i] := 2*A[i];
end;
procedure TForm1.FormCreate(Sender: TObject);
var
i: Integer;
begin
SetLength(Arr, 10);
for i := 0 to High(Arr) do
Arr[i] := i;
Test(Arr);
for i := 0 to High(Arr) do
ShowMessage(Arr[i].ToString);
end;
Run Code Online (Sandbox Code Playgroud)
SetLength保证它的参数的引用计数1在它返回时。