官术网_书友最值得收藏!

Arrays

Delphi supports two kinds of arrays. One is of a fixed size and has settable lower and upper bounds. We call them static arrays. Others have a lower bound fixed at zero, while the upper bound is variable. In other words, they can grow and shrink. Because of that, they are called dynamic arrays.

The following code fragment shows how static and dynamic arrays are declared in Delphi:

var
sarr1: array [2..22] of integer; // static array
sarr2: array [byte] of string; // static array
darr1: array of TDateTime; // dynamic array
darr2: TArray<string>; // dynamic array

Every array stores elements of some type. The compiler will treat these elements just the same as variables of that type. In the second declaration above, for example, the element type is string. This is a managed type and all 256 elements of the array will be initialized to nil automatically.

Static arrays are pretty dull. They have a constant size and as such are created exactly the same way as simple types (except that they typically use more space). Dynamic arrays, on the other hand, are similar to strings, but with a twist.

When you declare a dynamic array, it will start as empty and the variable will contain a nil pointer. Only when you change an array size (by using SetLength or a TArray constructor), memory will be allocated and a pointer to that memory will be stored in the dynamic array variable. Any change to array size will reallocate this storage memory—just like with the strings.

Modifying elements of an array is simple—again just like with the strings. An address of the element that is being modified is calculated and then item data is copied from one location to another. Of course, if array elements are not of a simple type, appropriate rules for that type will apply. Setting an element of array of string brings in the rules for the string type and so on.

When you assign one array to another, Delphi again treats them just the same as strings. It simply copies one pointer (to the array data) into another variable. At the end both variables contain the same address. A reference count in the array memory is also incremented. Again, just as strings.

The similarities with string types end here. If you now modify one element in one of the arrays, the same change will apply to the second array! There is no copy-on-write mechanism for dynamic arrays and both array variables will still point to the same array memory.

This is great from the efficiency viewpoint, but may not be exactly what you wanted. There's, luckily, a workaround that will split both arrays into two separate copies. Any time you call a SetLength on a shared array, the code will make this array unique, just like UniqueString does to strings. Even if the new length is the same as the old one, a unique copy of an array will still be made.

The following code from the DataTypes demo demonstrates this. Firstly, it allocates the arr1 array by using a handy syntax introduced in Delphi XE7. Then it assigns arr1 to arr2. This operation merely copies the pointers and increments the reference count. Both pointers and contents of the arrays are then shown in the log.

After that, the code modifies one element of arr1 and logs again. To complete the test, the code calls SetArray to make arr2 unique and modifies arr1 again:

procedure TfrmDataTypes.btnSharedDynArraysClick(Sender: TObject);
var
arr1, arr2: TArray<Integer>;
begin
arr1 := [1, 2, 3, 4, 5];
arr2 := arr1;
ListBox1.Items.Add(Format('arr1 = %p [%s], arr2 = %p [%s]',
[PPointer(@arr1)^, ToStringArr(arr1),
PPointer(@arr2)^, ToStringArr(arr2)]));

arr1[2] := 42;
ListBox1.Items.Add(Format('arr1 = %p [%s], arr2 = %p [%s]',
[PPointer(@arr1)^, ToStringArr(arr1),
PPointer(@arr2)^, ToStringArr(arr2)]));

SetLength(arr2, Length(arr2));
arr1[2] := 17;
ListBox1.Items.Add(Format('arr1 = %p [%s], arr2 = %p [%s]',
[PPointer(@arr1)^, ToStringArr(arr1),
PPointer(@arr2)^, ToStringArr(arr2)]));
end;

The output of the program shows that after the assignment both arrays point to the same memory and contain the same data. This doesn't change after arr1[2] := 42. Both arrays still point to the same memory and contain the same (changed) data.

After SetLength, however, arrays point to a separate memory address and changing arr1 only changes that array:

主站蜘蛛池模板: 乡宁县| 图们市| 温宿县| 屏东县| 铜川市| 定南县| 汉阴县| 石河子市| 阿克陶县| 太谷县| 安西县| 青川县| 长乐市| 遵化市| 当雄县| 万年县| 永吉县| 特克斯县| 邵阳市| 安义县| 五原县| 石嘴山市| 通许县| 乐东| 古丈县| 峨山| 连江县| 汉寿县| 保山市| 阜平县| 桂林市| 鄂温| 新巴尔虎右旗| 万载县| 库车县| 苏尼特右旗| 阿拉善右旗| 安吉县| 福安市| 沂源县| 信丰县|