Динамический массив, вызывающий недопустимое исключение указателя

У меня есть процедура, которая принимает динамический массив TData = TArray<Byte> в качестве параметра.

procedure DoStuff(const Input: TData);
begin
  // do nothing
end;

И функция, возвращающая динамический массив.

function SomeData: TData;
begin
  Result := [1, 2];
end;

Когда я использую процедуру в приведенном ниже примере, DoStuff получает следующие данные (1, 2, 3, 1, 3), но после завершения DoStuff я получаю исключение EInvalidPointer.

procedure TForm1.Button1Click(Sender: TObject);
begin    
  DoStuff([1, 2, 3] + SomeData);
end;

Вызов DoStuff([1, 2] + SomeData); не приводит к ошибке, кажется, становится обидным, когда массив больше 4 элементов. Если я использую временную переменную для хранения массива, DoStuff по-прежнему получает (1, 2, 3, 1, 2), но ошибки не возникает.

procedure TForm1.Button2Click(Sender: TObject);
var
  Temp: TData;
begin
  Temp := [1, 2, 3] + SomeData;

  DoStuff(Temp);
end;

Похоже, что исключение указателя связано с тем, как один из динамических массивов освобождается, когда они выходят из области видимости.

Должен ли я использовать динамические массивы таким образом? При работе это решило мою текущую проблему очень чисто.

Я также попытался использовать array of Byte; вместо TArray<Byte>;, но имел тот же результат.

Полная тестовая единица:

unit Main;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants,
  System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;

type
  TData = TArray<Byte>;

  TForm1 = class(TForm)
    Button1: TButton;
    Button2: TButton;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

procedure DoStuff(const Input: TData);
function SomeData: TData;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
begin
  DoStuff([1, 2, 3] + SomeData);
end;

procedure TForm1.Button2Click(Sender: TObject);
var
  Temp: TData;
begin
  Temp := [1, 2, 3] + SomeData;

  DoStuff(Temp);
end;

procedure DoStuff(const Input: TData);
begin
  // do nothing
end;

function SomeData: TData;
begin
  Result := [1, 2];
end;

end.

Ответ 1

У вашего кода нет дефектов, и любые ошибки могут быть связаны только с ошибками компилятора /RTL.

Поддержка динамических массивных литералов и оператора динамического массива + была несколько неоднородной при первом выпуске. Эти функции были добавлены в XE7, и я считаю, что большинство ошибок были сглажены XE8.

Я предполагаю, что вы используете XE7 или, возможно, версию уровня, которая по-прежнему содержит более непонятную ошибку, чем многие очевидные из XE7.

Ваши параметры выглядят так:

  • Обновление до более поздней версии Delphi.
  • Работайте над кодом, избегая использования оператора + с динамическими массивами и/или динамическими массивами.

Я все еще использую XE7 и обдумываю проблемы с моей собственной общей функцией конкатенации. Пример того, как это сделать, можно найти здесь: fooobar.com/info/505657/...

Такое обходное решение помогает избежать проблем с оператором +, но не в том случае, если проблема связана с обработкой литералов массива. Если ваша проблема связана с литералами массива, тогда вам может понадобиться использовать TData.Create(1, 2, 3) вместо [1, 2, 3].

Если дефект присутствует в более поздних версиях, отправьте отчет об ошибке в портал качества Embarcadero.