Delphi - Управление списком TList с динамическим массивом c - PullRequest
1 голос
/ 24 апреля 2020

У меня есть компонент для построения сплайна, аргумент для процедуры сплайна в массиве TPoint. Теперь я хочу создать n динамический c массив TPoint, сохранить его в TList и после отзыва для построения сплайнов.

PS Delphi 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;

... и не работают. : - (

1 Ответ

3 голосов
/ 24 апреля 2020

Non-Generi c System.Classes.TList - это просто контейнер необработанных указателей, он не имеет понятия о том, что он содержит. Динамические c массивы подсчитываются по ссылкам, и 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;

Лучшее решение - использовать Generi c System.Generics.Collections.TList<T>, где T равно 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;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...