将TArray <x>类型转换为X?</x>数组是否安全?

时间:2012-09-07 15:00:48

标签: delphi generics casting delphi-xe2 dynamic-arrays

今天我发现了编译器错误(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>强制转换,引用计数等了解不足以确信这是安全的。

是否有人知道这种或那种方式是否会在运行时生成正确的代码?

3 个答案:

答案 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 ..,否则此类constvar会按值传递并复制到堆栈中:

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),这意味着TObjectarray of T在Delphi中确实存在一些实现差异。它们肯定会产生不同类型的RTTI,至少。当Delphi编译器开始在HPP文件中为Delphi TArray<T>类型而不是TArray typedef输出array of ... typedef时,我的一些C ++代码中出现问题的根本原因就是失败。< / p>