Wod*_*dzu 5 delphi memory-management delphi-2009 multidimensional-array
今天我偶然发现了导致我的阵列损坏的问题.这是一个可重现的测试用例:
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.
Run Code Online (Sandbox Code Playgroud)
我想最后的内存损坏SetLength只是使用不当的一个症状Move.有人可以向我解释我做错了什么以及如何Move在这种情况下正确使用?
在原始问题中,我在循环中从BoundryInfo中删除元素,这就是我调用的原因 Finalize(BoundryInfo[BoundryLength])
Arn*_*hez 10
在你的代码中,
Move(BoundryInfo[PointIndex+1], BoundryInfo[PointIndex],
((BoundryLength - 1) - PointIndex) * SizeOf(BoundryInfo[PointIndex]));
Run Code Online (Sandbox Code Playgroud)
将指针复制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
Run Code Online (Sandbox Code Playgroud)
简而言之:
move();move().通过使用Move和颠覆动态数组引用计数机制,您只需为自己设置陷阱.我强烈建议你坚持标准机制,让编译器担心细节.每次都会让他们正确.
for i := 0 to high(BoundaryInfo)-1 do
BoundaryInfo[i] := BoundaryInfo[i+1];
SetLength(BoundaryInfo, Length(BoundaryInfo)-1);
Run Code Online (Sandbox Code Playgroud)