Являются ли члены в заявлении с оператором AND всегда проверены в данном порядке?

Я хотел бы знать, может ли следующий код когда-либо провалиться с нарушением прав доступа или если он безопасен. Является ли первый член оператора с оператором AND всегда проверяемым как первым, так и может быть (с помощью некоторой оптимизации компилятора или что-то в этом роде) проверил второй как первый?

var
  Item: TSomething;

procedure DoSomething;
begin
  if Assigned(Item) and (Item.SomeProperty) then
    DoSomethingElse;
end;

Является ли код выше определенно безопасным?

Спасибо!

Ответ 1

Код безопасен, если булевая оценка короткого замыкания активна:

В состоянии {$ B-} компилятор генерирует код для вычисления Boolean выражения короткого замыкания, что означает, что оценка останавливается, как только результат всего выражения становится очевидным в порядке слева и справа.

Это немного запутанно, так как директива B (или BOOLEVAL с длинным именем) должна быть отключена, чтобы включить оценку короткого замыкания ON...

См. также Приоритет оператора.

Ответ 2

Это зависит от типа Item.SomeProperty. Если это вариант, или если перед ним есть вариант, который будет оцениваться, он будет оцениваться и вызывать AV.

Изменить: Забудьте указать обходной путь: Если тип SomeProperty имеет тип Variant, вы можете использовать

  if Assigned(Item) and StrToBool(Item.SomeProperty) then

Проводят некоторое время, чтобы преобразовать переменную в String, а затем вернуться к логическому, но в аренду он может удовлетворить все случаи, когда он является истинным/ложным/небытием.

Ниже приведен тестовый пример:

unit Unit4;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, Generics.Collections;

type
  TTestObj = class
  public
    V : Variant;
    I : Integer;
  end;

  TForm4 = class(TForm)
    btn1: TButton;
    btn2: TButton;
    btn3: TButton;
    procedure btn1Click(Sender: TObject);
    procedure btn2Click(Sender: TObject);
    procedure btn3Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
    TOV : TTestObj;
  end;

var
  Form4: TForm4;

implementation

{$R *.dfm}

procedure TForm4.btn1Click(Sender: TObject);
begin
  if Assigned(TOV) and (TOV.I = 10) then
    ShowMessage('You will never see this though no AV!');
end;

procedure TForm4.btn2Click(Sender: TObject);
begin
  if Assigned(TOV) and StrToBool(TOV.V) then
    ShowMessage('You will not see AV with StrToBool!');
  if Assigned(TOV) and TOV.V then
    ShowMessage('You will never see this but AVed!');
end;

procedure TForm4.btn3Click(Sender: TObject);
var
  V : Variant;
begin
  V := False;
  if Assigned(TOV) and V and (TOV.I = 10) then
    ShowMessage('You will see AV!');
end;

end.

Ответ 3

Безопасно называть указанное вами условие Посмотрите

У меня есть строковый список, и я проверил два условия

    Strinlst : TStringlist; 

      Tester.pas.169: if ( (Assigned(Strinlst)) and(Strinlst.count<>6)) then
      0052A3CC 8BB3E4030000     mov esi,[ebx+$000003e4]
      0052A3D2 85F6             test esi,esi              //check if Strinlst is assigned
      0052A3D4 741F             jz $0052a3f5              //jump out if not true 
      0052A3D6 8BC6             mov eax,esi
      0052A3D8 8B10             mov edx,[eax]
      0052A3DA FF5214           call dword ptr [edx+$14]
      0052A3DD 83F806           cmp eax,$06               //compare the count
      0052A3E0 7413             jz $0052a3f5              //jump to the result

То же самое относится к условию в другом порядке

      Tester.pas.169: if ( (Strinlst.count<>6) and (Assigned(Strinlst)) ) then
      0052A3CB 8B83E4030000     mov eax,[ebx+$000003e4]
      0052A3D1 8B10             mov edx,[eax]
      0052A3D3 FF5214           call dword ptr [edx+$14]   //get the count
      0052A3D6 83F806           cmp eax,$06                //compare the count    
      0052A3D9 741B             jz $0052a3f6               //jump if not true  
      0052A3DB 83BBE403000000   cmp dword ptr [ebx+$000003e4],$00 //compare if Strinlst is assigned
      0052A3E2 7412             jz $0052a3f6              //jump if false

так что, конечно, порядок условий соблюдается слева направо