16

今天我发现了一个编译器错误(QC#108577)。

以下程序无法编译:

program Project1;
{$APPTYPE CONSOLE}

procedure P(M: TArray<TArray<Integer>>);
begin
  SetLength(M, 1, 2);
end;

begin
end.

编译器SetLength在线上堵嘴并说:

[dcc32 Error] E2029 ')' expected but ',' found

我知道我可以这样修复它:

procedure P(M: TArray<TArray<Integer>>);
var
  i: Integer;
begin
  SetLength(M, 1);
  for i := low(M) to high(M) do
    SetLength(M[i], 2);
end;

但自然我很想避免诉诸于此。

以下变体编译并且似乎可以工作:

procedure P(M: TArray<TArray<Integer>>);
type
  TArrayOfArrayOfInteger = array of array of Integer;
begin
  SetLength(TArrayOfArrayOfInteger(M), 1, 2);
end;

我对动态数组、TArray<T>强制转换、引用计数等的实现细节知之甚少,无法确信这是安全的。

有没有人知道足够的方式来说明这是否会在运行时产生正确的代码?

4

3 回答 3

18

编译器内在过程SetLength在堆栈上动态构造一个维度数组,并调用DynArraySetLength任何动态数组,无论它是通用的还是非通用的。如果通用数组在结构上与常规动态数组不兼容,则可能不会调用用于设置长度的相同实现。

事实上,作为多维数组的替代品的报价文档。也可以用来代替类型转换,但我看不出有任何理由偏爱其中一种。 DynArraySetLengthSetLengthDynArraySetLength

于 2012-09-07T17:07:30.943 回答
3

根据泛型实现的设计,使用手动映射array of array of Integer将起作用。

但是在这里使用泛型没有任何好处!

只需代码:

type
  TArrayOfArrayOfInteger = array of array of Integer;

procedure P(M: TArrayOfArrayOfInteger);
begin
  SetLength(TArrayOfArrayOfInteger, 1, 2);
end;

另请注意,此类TArray<>orarray of ..是按值传递的,并在堆栈上复制,除非您指定constor var

procedure P(var M: TArrayOfArrayOfInteger);
begin
  SetLength(TArrayOfArrayOfInteger, 1, 2);
end; // now caller instance of the parameter will be resized

var A: TArrayOfArrayOfInteger;
...
A := nil;
P(A);
assert(length(A)=1);
assert(length(A[0])=2);
于 2012-09-07T16:33:41.043 回答
2

我最近被以下事实所困扰,DynamicArray<T>TArray<T>C++ 中和实际上是不同的实现(DynamicArray是一个独立的类,而是TArray一个TObject后代),这意味着在 Delphi 中array of TTArray<T>确实存在一些实现差异。至少,他们肯定会产生不同类型的 RTTI。这是我的一些 C++ 代码中出现问题的根本原因,当 Delphi 编译器开始TArray在 HPP 文件中为 Delphiarray of ...类型而不是DynamicArraytypedef 输出 typedef 时,该代码开始失败。

于 2012-09-07T23:26:39.357 回答