2017-09-28 2 views
12

Delphi Tokyoの例外処理が以前のDelphiのバージョンと少し違っていることが判明しました。Delphi Tokyo例外が関数の結果を設定しないようにする

function FuncTest: integer; 
begin 
    Result := 1; 
    try 
    raise Exception.Create('Error Message'); 
    finally 
    Result := 2; 
    end; 
end; 

function Test:integer; 
begin 
    Result:=0; 
    try 
    Result:=FuncTest; 
    finally 
    ShowMessage(Result.ToString); 
    end; 
end; 

以前のDelphiのバージョンでは、メッセージボックスに "2"、東京 - "0"と表示されます。 これは東京バグですか、例外をこのように扱うべきではありませんか?

答えて

10

東京の動作は正しいです。例外を発生させる関数は値を返しません。これまで、実装の詳細に頼ってきました。

Result:=FuncTest; 

これは、次のように実行します:

  1. FuncTestが呼び出され

    は、このコードを考えてみましょう。
  2. Resultが割り当てられます。

ここで、ステップ1は例外を発生させるため、ステップ2は実行されません。

もし何か言えば、あなたが以前のバージョンから報告した動作は疑わしいと言います。この機能では:

function Test:integer; 
begin 
    Result:=0; 
    try 
    Result:=FuncTest; 
    finally 
    ShowMessage(Result.ToString); 
    end; 
end; 

声明Result:=FuncTestは、例外が発生しますので、Resultは、そのステートメントで変更すべきではありません。それを考えるもう一つの方法は、関数が呼び出されるが代入は実行されないということです。デルファイABIの問題の


一つは、関数の戻り値は、時々暗黙varパラメータとして実装されています。つまり、割り当てが行われる場合とされない場合があります。証明するために:

{$APPTYPE CONSOLE} 

uses 
    System.SysUtils; 

type 
    TRec1 = record 
    X1: NativeInt; 
    end; 

    TRec2 = record 
    X1: NativeInt; 
    X2: NativeInt; 
    end; 

function GetRec1: TRec1; 
begin 
    Result.X1 := 1; 
    raise Exception.Create(''); 
end; 

function GetRec2: TRec2; 
begin 
    Result.X1 := 1; 
    raise Exception.Create(''); 
end; 

procedure Main; 
var 
    Rec1: TRec1; 
    Rec2: TRec2; 
begin 
    Rec1 := Default(TRec1); 
    Writeln(Rec1.X1); 
    try 
    Rec1 := GetRec1; 
    except 
    end; 
    Writeln(Rec1.X1); 

    Rec2 := Default(TRec2); 
    Writeln(Rec2.X1); 
    try 
    Rec2 := GetRec2; 
    except 
    end; 
    Writeln(Rec2.X1); 
end; 

begin 
    Main; 
    Readln; 
end. 

この出力:かなり残念です

 
0 
0 
0 
1 

を。呼び出し元の変数を変更することはできませんが、値の戻り値ではなく暗黙的なvarパラメータを使用すると、この漏れが許容されます。私の見解では、これはデルファイABIの設計における深刻な欠陥です。これは他のほとんどの言語では見つけられない欠陥です。あなたのコードで


戻り値の型がレジスタに転送されるため、何varパラメータがありません。この場合、2を出力するDelphiのバージョンは破損しています。

基本的には、あなたのコードは誤解されています。関数が例外を発生させた場合は、戻り値が正しく定義されていないと想定する必要があります。

最後に、コードは0をXE3とXE7に出力するので、どれくらい前に戻って2の値を参照する必要があるのでしょうか。

+0

以前のDelphiのバージョンはありませんが、x64コンパイラが導入されたのはXE2だと思います。Aは、FuncTestが1(tryブロックなし)または2を返すという事実に依存するコードを持っています。私はそれを取得しました。例外は発生しません。 – Molochnik

+1

関数が例外を発生させても問題ありません。間違っているのは、その場合に値が返されることを期待することです。この場合、戻り値の型はレジスタに収まるため、ABIは問題ありません。「var」パラメータは発行されません。しかし、はい、XE2 64ビットはいくつか良い点がありました。 –

+0

あなたは関数がe、g、レコードを返した場合、問題はないだろうということを意味しますか? – Molochnik

関連する問題