Этот пример можно упростить, удалив все ссылки на дженерики:
{$APPTYPE CONSOLE}
var
x, y: array of Integer;
begin
SetLength(x, 1);
x[0] := 42;
y := x;
Writeln(x[0]);
y[0] := 666;
Writeln(x[0]);
end.
Результат:
42
666
Причина этого в том, что динамический массив является ссылочным типом. Когда вы присваиваете переменную типа динамического массива, вы берете другую ссылку, а не делаете копию.
Вы можете решить эту проблему, заставив ссылку быть уникальной (то есть иметь только простую ссылку). Есть несколько способов добиться этого. Например, вы можете вызвать SetLength
для массива, который вы хотите сделать уникальным.
{$APPTYPE CONSOLE}
var
x, y: array of Integer;
begin
SetLength(x, 1);
x[0] := 42;
y := x;
SetLength(y, Length(y));
Writeln(x[0]);
y[0] := 666;
Writeln(x[0]);
end.
Выход:
42
42
Итак, в вашем коде вы можете написать это так:
MyList:=TList<TMyRec>.Create;
SetLength(MyRec.MyArr,5);
MyRec.MyArr[0]:=8; // just for demonstration
MyRec.Name:='Record 1';
MyRec.Completed:=true;
MyList.Add(MyRec);
SetLength(MyRec.MyArr,5); // <-- make the array unique
MyRec.MyArr[0]:=5; // just for demonstration
MyRec.Name:='Record 2';
MyRec.Completed:=false;
MyList.Add(MyRec);
Вы можете использовать множество других способов обеспечения уникальности, включая Finalize
, назначение nil
, Copy
и т. д.
Эта проблема подробно описана в документации. Вот соответствующие выдержки:
Если X и Y являются переменными одного и того же типа динамического массива, X := Y указывает X на тот же массив, что и Y. (Перед выполнением этой операции нет необходимости выделять память для X.) В отличие от строк и статических массивов, копирование -on-write не используется для динамических массивов, поэтому они не копируются автоматически перед записью. Например, после выполнения этого кода:
var
A, B: array of Integer;
begin
SetLength(A, 1);
A[0] := 1;
B := A;
B[0] := 2;
end;
значение A[0] равно 2. (Если бы A и B были статическими массивами, A[0] все равно было бы равно 1.) Присвоение индекса динамического массива (например, MyFlexibleArray[2] := 7) не перераспределить массив. Индексы вне допустимого диапазона не сообщаются во время компиляции. Напротив, чтобы сделать независимую копию динамического массива, вы должны использовать глобальную функцию копирования:
var
A, B: array of Integer;
begin
SetLength(A, 1);
A[0] := 1;
B := Copy(A);
B[0] := 2; { B[0] <> A[0] }
end;
person
David Heffernan
schedule
31.01.2014