首页 > 解决方案 > Delphi - 使用动态数组管理 TList

问题描述

我有一个用于绘制样条曲线的组件,它是 TPoint 数组中样条曲线过程的参数。现在,我想创建 n 个 TPoint 的动态数组,将其保存在 TList 中,并在调用后绘制样条曲线。

PS德尔福XE5

例子:

var
  l: TList;

procedure CreateSpline;
var i, x: byte;
    p: TPoint;
    a: array of TPoint;
begin
    l := TList.Create;

    for x := 0 to 9 do  // create 10 splines
    begin
        SetLength(a, Random(10) + 5);   Each spline has 5<n<15 points
        for i := 0 to High(a) do
        begin
            p.X := Random(200) - 100;   // X coord
            p.Y := Random(200) - 100;   // Y coord
            a[i] := p;                  // add point to array
        end;
        l.Add(a);                       // add array to TList
    end;
end;

procedure DrawSpline;
var i: byte;
    a: array of TPoint;
begin
    for i := 0 to 9 do
    begin
        a := l[i];
        xyPlot.Spline(a);  // Draw the spline (xyPlot is the graphic component)
    end;
end;

...并且不工作。:-(

标签: delphi

解决方案


非泛型System.Classes.TList只是一个原始指针的容器,它不知道它持有什么。动态数组是引用计数的,TList不会为您管理引用计数,因此您必须手动执行以确保当数组在列表中时引用计数增加,例如:

ar
  l: TList;

procedure CreateSpline;
var
  i, x: byte;
  p: TPoint;
  a: TArray<TPoint>;
  aptr: Pointer;
begin
  l := TList.Create;

  for x := 0 to 9 do  // create 10 splines
  begin
    SetLength(a, Random(10) + 5);   // Each spline has 5<n<15 points
    for i := 0 to High(a) do
    begin
      p.X := Random(200) - 100;     // X coord
      p.Y := Random(200) - 100;     // Y coord
      a[i] := p;                    // add point to array
    end;
    TArray<TPoint>(aptr) := a;
    try
      l.Add(aptr);                  // add array to TList
    except
      TArray<TPoint>(aptr) := nil;
      raise;
    end;
    a := nil;
  end;
end;

{ alternatively:

procedure CreateSpline;
var
  i, x: byte;
  p: TPoint;
  a: TArray<TPoint>;
begin
  l := TList.Create;

  for x := 0 to 9 do  // create 10 splines
  begin
    SetLength(a, Random(10) + 5);   // Each spline has 5<n<15 points
    for i := 0 to High(a) do
    begin
      p.X := Random(200) - 100;     // X coord
      p.Y := Random(200) - 100;     // Y coord
      a[i] := p;                    // add point to array
    end;
    l.Add(Pointer(a));              // add array to TList
    Pointer(a) := nil;
  end;
end;
}

procedure DrawSpline;
var
  i: byte;
  a: TArray<TPoint>;
begin
  for i := 0 to 9 do
  begin
    a := TArray<TPoint>(l[i]);
    xyPlot.Spline(a);  // Draw the spline (xyPlot is the graphic component)
  end;
end;

...

// later, you need to decrement the refcounts before freeing/clearing the TList...

var
  i: byte;
  aptr: Pointer;
begin
  for i := 0 to 9 do
  begin
    aptr := l[i];
    TArray<TPoint>(aptr) = nil;
  end;
  l.Free;
end;

更好的解决方案是使用 GenericSystem.Generics.Collections.TList<T>代替,其中Tis TArray<TPoint>. 然后将为您正确管理引用计数,例如:

ar
  l: TList<TArray<TPoint>>;

procedure CreateSpline;
var
  i, x: byte;
  p: TPoint;
  a: TArray<TPoint>;
begin
  l := TList<TArray<TPoint>>.Create;

  for x := 0 to 9 do  // create 10 splines
  begin
    SetLength(a, Random(10) + 5);   // Each spline has 5<n<15 points
    for i := 0 to High(a) do
    begin
      p.X := Random(200) - 100;     // X coord
      p.Y := Random(200) - 100;     // Y coord
      a[i] := p;                    // add point to array
    end;
    l.Add(a);                       // add array to TList
  end;
end;

procedure DrawSpline;
var
  i: byte;
  a: TArray<TPoint>;
begin
  for i := 0 to 9 do
  begin
    a := l[i];
    xyPlot.Spline(a);  // Draw the spline (xyPlot is the graphic component)
  end;
end;

...

l.Free;

推荐阅读