2016-10-12 6 views
21

Delphiで暗黙的なクラス演算子を使用して動的配列を含むレコードを初期化できるかどうかを確認しようとしています(Berlin 10.1 upd 1「暗黙の」クラス演算子を持つ動的配列を含むDelphiレコードの初期化

ci iA r1 r2 r3 
1 1 1 1 49694764491115752 
2 2 2 2 11570520 
3 3 3 3 0 
4 4 4 4 0 
5 5 5 5 0 
  • TREC Iを初期化する動的配列を含むレコードのタイプである。)

    添付のプログラムは、次の出力が生成します。

  • ciは整数の定数配列です。
  • iaは、整数の動的配列です。
  • r1、r2、r3は、異なる方法で初期化されるタイプTRecのレコードです。

出力からわかるように、定数を使用する最初の2つの割り当て(r1、r2)は、期待どおりに機能します。 3番目の割り当てr3 := iArrayはコンパイラによって受け入れられますが、結果は破損しています。デバッガではTRec.Implicitvの値が既に間違っていることが示されています。

ここで何が問題になりますか?これはまったく可能ですか?

program Project5; 

{$APPTYPE CONSOLE} 

{$R *.res} 

type 
    TRec = record 
    iArray: array of UInt64; 
    class operator Implicit(const v: array of UInt64): TRec; 
    end; 

{ TRec } 

class operator TRec.Implicit(const v: array of UInt64): TRec; 
var 
    i: integer; 
begin 
    setlength(Result.iArray, Length(v)); 
    for i := 0 to High(v) do 
    Result.iArray[i] := v[i]; 
end; 

const 
    ciArray: array [0 .. 4] of UInt64 = (1, 2, 3, 4, 5); 

var 
    i   : integer; 
    iArray : array of UInt64; 
    r1, r2, r3: TRec; 

begin 
    iArray := [1, 2, 3, 4, 5]; 

    r1 := [1, 2, 3, 4, 5]; 
    r2 := ciArray; 
    r3 := iArray; 

    Writeln('ci iA r1 r1 r3'); 
    for I := 0 to High(ciArray) do 
    Writeln(ciArray[i], ' ', iArray[i], ' ', r1.iArray[i], ' ', r2.iArray[i], ' ', r3.iArray[i]); 

    readln; 

end. 
+1

確かに可能です。私は私の 'BigInteger'タイプ(http://www.rvelthuis.de/programs/bigintegers.html)でもそうしています。ただし、COW(Copy-On-Write)を実行するようにしてください。**配列**が変更されるたびに、そのコピーが一意のコピーであることを確認する必要があります。 –

+0

@RudyVelthuisコンパイラのバグはそれを可能にしません。あなたがそのバグを回避したり、ベンダーからの修正を得ない限り。 –

+0

さて、 'Implicit()'のdynarray * parameters *は特殊なケースです。それ以外の場合は動作します。レコードには、dynarrayを含めることができます。 –

答えて

19

そこにあるcodegenのバグを見つけたようです(Win64コンパイラにもあります)。生成されたasmを見て、コンパイラが演算子のオーバーロードのために間違った命令を生成するようです。そのため、誤った値がオペレータのオーバーロード内で配列内に終わるのです。これを品質ポータルで報告してください。同じメソッドの

Project109.dpr.46: r3 := iArray; 
0040B1F2 A1FC044100  mov eax,[$004104fc] 
0040B1F7 8945E8   mov [ebp-$18],eax 
0040B1FA 837DE800   cmp dword ptr [ebp-$18],$00 
0040B1FE 740B    jz $0040b20b 
0040B200 8B45E8   mov eax,[ebp-$18] 
0040B203 83E804   sub eax,$04 
0040B206 8B00    mov eax,[eax] 
0040B208 8945E8   mov [ebp-$18],eax 
0040B20B 8D4DD8   lea ecx,[ebp-$28] 
0040B20E 8B55E8   mov edx,[ebp-$18] 
0040B211 4A    dec edx 
0040B212 B8FC044100  mov eax,$004104fc // <-- wrong one 
0040B217 E87CF5FFFF  call TRec.&op_Implicit 

コード:

コードは悪い結果のために生成されますが、パラメータの型との暗黙のオペレータのための別のオーバーロードを追加することでこの問題を回避することができますしかし

Project109.dpr.47: r3 := TRec.Implicit(iArray); 
0040B22F A1FC044100  mov eax,[$004104fc] 
0040B234 8945E4   mov [ebp-$1c],eax 
0040B237 837DE400   cmp dword ptr [ebp-$1c],$00 
0040B23B 740B    jz $0040b248 
0040B23D 8B45E4   mov eax,[ebp-$1c] 
0040B240 83E804   sub eax,$04 
0040B243 8B00    mov eax,[eax] 
0040B245 8945E4   mov [ebp-$1c],eax 
0040B248 8D4DD4   lea ecx,[ebp-$2c] 
0040B24B 8B55E4   mov edx,[ebp-$1c] 
0040B24E 4A    dec edx 
0040B24F A1FC044100  mov eax,[$004104fc] // <-- correct one 
0040B254 E8CFF5FFFF  call TRec.Implicit 

TArray<UInt64>とコンパイラが正しいオーバーロードを選択するように、ローカル変数をその型として宣言します(この場合は間違ったコードを生成しません)。

しかし、これは、TArray<UInt64>の変数を渡し、Delphisの厳密な型ルールのために他の動的なarray of UInt64があるときは間違ったものを呼び出す場合にのみ機能することに注意してください。

更新:この不具合はRSP-16084で報告され、Delphi 10.2 Tokyoで修正されました。

+1

下に提出:https://quality.embarcadero.com/browse/RSP-16084 –

関連する問題