2017-09-28 79 views
12

Wykryto, że obsługa wyjątków w Delphi Tokyo zachowuje się nieco inaczej niż w poprzednich wersjach Delphi.Wyjątek Delphi Tokyo zapobiega wynikowi funkcji ustawień

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; 

We wcześniejszych wersjach Delphi w oknie komunikatu wyświetla się "2", Tokio - "0". Czy jest to błąd z Tokio, czy też wyjątki nie powinny być traktowane w ten sposób?

Odpowiedz

10

Zachowanie Tokio jest poprawne. Funkcja, która podnosi wyjątek, nie zwraca wartości. Do tej pory polegałeś na szczegółach implementacji.

Rozważmy następujący kod:

Result:=FuncTest; 

ten wykonuje się następująco:

  1. FuncTest jest tzw.
  2. Result jest przypisany.

Teraz, ponieważ krok 1 wywołuje wyjątek, krok 2 nie jest wykonywany.

Jeśli cokolwiek, chciałbym powiedzieć, że zachowanie zgłaszane przez wcześniejsze wersje jest wątpliwe. W tej funkcji:

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

Oświadczenie Result:=FuncTest podnosi wyjątek i tak Result nie powinny być modyfikowane przez tego oświadczenia. Innym sposobem, aby o tym pomyśleć, jest wywołanie funkcji, ale przypisanie nie jest wykonywane.


Jednym z problemów związanych z Delphi ABI jest to, że funkcja wartości powrotne są wdrażane jako ukrytych var parametrów. Co oznacza, że ​​zadanie może się zdarzyć lub nie. Aby wykazać, że:

{$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. 

This wyjścia:

 
0 
0 
0 
1 

co jest raczej rozczarowujące. Zmodyfikowanie zmiennej wywołującej nie powinno być możliwe, ale użycie niejawnego parametru var zamiast powrotu wartości umożliwia takie przeciekanie. Moim zdaniem jest to poważna usterka w projekcie Delphi ABI, wada, której nie można znaleźć w większości innych języków.


W kodzie nie ma parametr var ponieważ typ zwracany jest przekazywana w rejestrze. W takim przypadku każda wersja Delphi, która wyprowadza 2, jest zepsuta.

Zasadniczo twój kod jest błędny w swoich oczekiwaniach. Jeśli funkcja wywołuje wyjątek, musisz założyć, że wartość zwracana jest źle zdefiniowana.

Wreszcie, twój kod wyprowadza 0 w XE3 i XE7, więc zastanawiam się, jak daleko wstecz musisz iść, aby zobaczyć wartość 2.

+0

Nie mam wcześniejszej wersji Delphi, ale myślę, że to XE2, gdzie został wprowadzony kompilator x64.A ma kod, który opierał się na fakcie, że FuncTest zwraca 1 (bez bloku try) lub 2. Ok dostałem to, nie więcej funkcji zgłaszających wyjątki, tylko procedury. – Molochnik

+1

To jest w porządku, aby funkcja zgłaszała wyjątki. Co jest złe, to oczekiwać zwrotu wartości w takim przypadku. W tym przypadku, ponieważ typ powrotu pasuje do rejestru, ABI jest w porządku, nie ma problemów z parametrem "var". Ale tak, XE2 64 bit miał kilka dobrych problemów. –

+0

Masz na myśli to, że jeśli funkcja zwróciła e, g, rekord, to nie byłoby problemu? – Molochnik

Powiązane problemy