5

今日、アレイが破損する原因となる問題に遭遇しました。再現可能なテスト ケースを次に示します。

unit Unit40;

interface

type
  TVertex = record
    X, Y: Double;
  end;

  TEdge = record
    V1, V2: TVertex;
  end;
  TEdges = array of TEdge;

type
  TBoundryInfo = array of TEdges;

procedure MemoryCorrupt;

implementation

procedure MemoryCorrupt;
var
  BoundryInfo: TBoundryInfo;
  i, PointIndex, BoundryLength: Integer;
begin
  BoundryLength := 57;
  PointIndex := 0;
  SetLength(BoundryInfo, BoundryLength);
  for i := 0 to BoundryLength - 1 do
  begin
    if i <> 17 then
    begin
      SetLength(BoundryInfo[i], 1);
      BoundryInfo[i][0].V1.X := 1;
      BoundryInfo[i][0].V2.X := 1;
      BoundryInfo[i][0].V1.Y := 1;
      BoundryInfo[i][0].V2.Y := 1;
    end else
    begin
      SetLength(BoundryInfo[i], 2);
      BoundryInfo[i][0].V1.X := 1;
      BoundryInfo[i][0].V2.X := 1;
      BoundryInfo[i][0].V1.Y := 1;
      BoundryInfo[i][0].V2.Y := 1;
      BoundryInfo[i][1].V1.X := 1;
      BoundryInfo[i][1].V2.X := 1;
      BoundryInfo[i][1].V1.Y := 1;
      BoundryInfo[i][1].V2.Y := 1;
    end;
  end;
  BoundryLength := 9;
  SetLength(BoundryInfo, BoundryLength);
  Move(BoundryInfo[PointIndex+1], BoundryInfo[PointIndex],
    ((BoundryLength - 1) - PointIndex) * SizeOf(BoundryInfo[PointIndex]));
  Dec(BoundryLength);
  Finalize(BoundryInfo[BoundryLength]);
  SetLength(BoundryInfo, BoundryLength); //After this, arrays contains garbage
  BoundryInfo[0][0].V1.X := 3;
end;

end.

SetLength最後の後のメモリ破損は、 の不適切な使用の兆候にすぎないと思いますMove。誰かが私に何が間違っているのかMove、この場合に適切に使用する方法を説明してもらえますか?

元の問題では、ループで BoundryInfo から要素を削除しています。そのため、呼び出していますFinalize(BoundryInfo[BoundryLength])

4

2 に答える 2

10

あなたのコードでは、

Move(BoundryInfo[PointIndex+1], BoundryInfo[PointIndex], 
  ((BoundryLength - 1) - PointIndex) * SizeOf(BoundryInfo[PointIndex]));

のポインタをBoundryInfo[PointIndex+1]にコピーしますBoundryInfo[PointIndex]。このポインターは別の動的配列であるため、参照カウントに注意する必要があります。

あれは:

SetLength(BoundryInfo[PointIndex],0); // release memory
Move(BoundryInfo[PointIndex+1], BoundryInfo[PointIndex], 
  ((BoundryLength - 1) - PointIndex) * SizeOf(BoundryInfo[PointIndex]));
PPointerArray(BoundryInfo)^[BoundryLength-1] := nil; // avoid GPF

要するに:

  • 中にオーバーライドされる項目を確定しますmove()
  • によって複製される最新の項目に nil を書き込みmove()ます。
于 2012-08-24T14:50:55.463 に答える