今天我发现了编译器错误(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>
强制转换,引用计数等了解不足以确信这是安全的。
是否有人知道这种或那种方式是否会在运行时生成正确的代码?
答案 0 :(得分:18)
编译器内部过程SetLength
在堆栈上构建一个维度数组,并为任何动态数组调用DynArraySetLength
,无论是否通用。如果通用数组在结构上与常规动态数组不兼容,则可能不会调用用于设置长度的相同实现。
事实上,DynArraySetLength
的{{3}}提供了SetLength
作为多维数组的替代方案。也可以使用DynArraySetLength
代替类型转换,但我认为没有理由偏好其中一个。
答案 1 :(得分:3)
通过设计的泛型实现,使用array of array of Integer
的手动地图将起作用。
但是在这里使用泛型没有任何好处!
只需代码:
type
TArrayOfArrayOfInteger = array of array of Integer;
procedure P(M: TArrayOfArrayOfInteger);
begin
SetLength(TArrayOfArrayOfInteger, 1, 2);
end;
另请注意,除非您指定TArray<>
或array of ..
,否则此类const
或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);
答案 2 :(得分:2)
我最近被C ++中的DynamicArray<T>
和TArray<T>
实际上以不同方式实现的事实所困扰(DynamicArray
是一个独立的类,而TArray
是{{1} } descendant),这意味着TObject
和array of T
在Delphi中确实存在一些实现差异。它们肯定会产生不同类型的RTTI,至少。当Delphi编译器开始在HPP文件中为Delphi TArray<T>
类型而不是TArray
typedef输出array of ...
typedef时,我的一些C ++代码中出现问题的根本原因就是失败。< / p>