- お知らせ -
  • 当wikiのプログラムコードの表示を直してみました(ついでに長い行があると全体が下にぶっ飛ぶのも修正)。不具合があればBBSまでご連絡下さい。

はじめに Edit

一言で言うと、Delphiの動的配列は参照カウンタつきポインタです。
それ以上でもそれ以下でも無いです。

スコープが外れると自動的に開放してくれるので「string のようなものだ」と思っていると痛い目に合います。
「代入したときは参照カウンタをインクリメント」してくれ、
「スコープが外れたときは、参照カウンタをデクリメントし、0になったら自動的に開放」はしますが、「書き換えた時にコピー(copy on write)」はしてくれないのです。

いや、まあ、この辺のことは、ヘルプの「動的配列」のところに書いてあるんですが。

検証例 Edit

ソースコード Edit

program dynarray;

{$APPTYPE CONSOLE}
uses
  Windows, Types;

const DefaultLength = 10;

procedure PrintArray(const aMessage: string; const aArray: TIntegerDynArray);
var i: Integer;
begin
  Write(aMessage);
  for i := Low(aArray) to High(aArray) do
    Write(aArray[i],  ' ');
  Writeln;
end;

procedure DynamicArrayTest;
var
  i: Integer;
  Array1, Array2: TIntegerDynArray;
begin
  // array1の確保と変更
  SetLength(Array1, DefaultLength);
  for i := Low(Array1) to High(Array1) do
    Array1[i] := i;
  // array1 を array2 にコピー
  Array2 := Array1;
  Writeln('array1 を array2 に直接代入');
  PrintArray(' Array1: ', Array1);
  PrintArray(' Array2: ', Array2);

  // array2 を変更
  for i := Low(Array2) to High(Array2) do
    Array2[i] := 1;
  Writeln('array2 を変更');
  PrintArray(' Array1: ', Array1);
  PrintArray(' Array2: ', Array2);

  // array1 を変更
  for i := Low(Array1) to High(Array1) do
    Array1[i] := 2;
  Writeln('array1 を変更');
  PrintArray(' Array1: ', Array1);
  PrintArray(' Array2: ', Array2);

  // array2 を確保と変更
  SetLength(Array2, DefaultLength);
  for i := Low(Array2) to High(Array2) do
    Array2[i] := 3;
  Writeln('array2 を確保し、変更');
  PrintArray(' Array1: ', Array1);
  PrintArray(' Array2: ', Array2);
end;

begin
  DynamicArrayTest;
end.

出力例 Edit

> dynarray.exe 
array1 を array2 に直接代入
 Array1: 0 1 2 3 4 5 6 7 8 9 
 Array2: 0 1 2 3 4 5 6 7 8 9 
array2 を変更
 Array1: 1 1 1 1 1 1 1 1 1 1 
 Array2: 1 1 1 1 1 1 1 1 1 1 
array1 を変更
 Array1: 2 2 2 2 2 2 2 2 2 2 
 Array2: 2 2 2 2 2 2 2 2 2 2 
array2 を確保し、変更
 Array1: 2 2 2 2 2 2 2 2 2 2 
 Array2: 3 3 3 3 3 3 3 3 3 3 

arrya2 を変更すると、array1まで変わっています。
また array1 を変更すると、array2まで変わっています。
これが stringになると、copy on writeが働いて、array2 を変更しても、
array1 は変わらないわけですね

当然ながらarray2を別に再確保した場合は、変更しても array1に影響していません。

対策 Edit

SetLengthして for ループで1つ1つコピーしてもいいのですが、面倒ですので、
copyを使います。

array2 := copy(array1, 0, Length(array1));

参考リンク Edit


  • "// array1" を変更 のところで、array1でなくarray2に代入していたのを修正 -- TOBY 2003-08-12 (火) 07:11:20
  • array of IntegerをTIntegerDynArrayに修正 -- TOBY 2008-10-21 (Tue) 16:23:02
  • Glömde jag säga att det är den bästa sidan i Sverige med hockeysnack.Det är uppdateringar hela tiden,hur hinner du :-Orfolst)ömare -- Johannah? 2017-01-24 (Tue) 15:17:16


Front page   Edit Freeze Diff Backup Upload Copy Rename Reload   New Pages Search Recent changes   Help   RSS of recent changes
Last-modified: 2017-01-24 Tue 15:17:17 JST (206d)