Delphi.cz

Český portál Delphi

Případ očekávaného Access Violation

Je vedro tak to trošku okořeníme. Mějme následující kód a odhadněte bez krokování, kde a zda vůbec program spadne. Je to umělá ukázka reálné situace, kterou jsem ale trošku zamaskoval ať je to zábavnější.

Možnosti k přemýšlení: spadne to protože volám metodu na nil objektu, spadne to protože TButton v console, spadne to protože TButton má taky Click, spadne to protože se snažím vypsat Caption a to je řetezec, spadne to protože se snažím nastavit Caption a to teprve nemůže projít, spadne to protože mám lokální proměnnou v metodě u nil objektu, spadne to protože přiřazují do lokální proměnné, spadne to protože čtu lokální proměnnou nil objektu, spadne to náhodou a jen někdy.

Nebo to v klidu projde vše. Jako je to trošku vyšší level, ale zkuste.

program TestAV;

{$APPTYPE CONSOLE}

{$R *.res}

uses
  WinApi.Windows, System.SysUtils, System.Classes, WinApi.Messages, Vcl.StdCtrls;
type
  TTestButton = class(TButton)
  public
    procedure Click;
  end;

  procedure TTestButton.Click;
  var
    x: Integer;
  begin
    writeln('button.Click'); // Line A
    writeln(Caption);        // Line B
    Caption := 'Button 23';  // Line C
    x := ImageIndex;         // Line D
    writeln(IntToStr(x));    // Line E
  end;

var
  t: TTestButton;
begin
  try
    t:=nil;
    t.Click;                 // Line F
    t.Free;                  // line G
  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
  readln;
end.

Volání metody na nil objektu projde v případě, že se nedotknete proměnných objektu. Interně to funguje tak, že metoda objektu je kus společného kódu, který v prvním parametru (skrytém) dostane adresu na data objektu. V našem případě je to nil, a do té doby, než na data šáhneme je to v klidu.

Metoda Free má test, zda není volaná na nil objektu. Tím máme vyřešené A, F, G.

Zbývá B, C, D, E.

Lokální proměnná je v pohodě, pokud do ní nepřiřadíme něco z objektu. Takže E je taky OK. Proč to nespadne na B a C? Tady je to ode mne trošku zákeřné, protože Caption je property, která má čtecí a zápisovou metodu a ty mají z důvodu Win32 API a posílání zpráv pro jistotu test na nil, takže projdou a můžete to vzít jako zákeřnost pro ilustraci.

A zbývá nám D, což je sice taky property, ale pro čtení nemá metodu a čte přímo data objektu (pro rychlost) a zde konečně narazí kosa na kámen a výsledkem je AV. Prostě při jakémkoliv kontaktu s daty objektu v našem případě narazíme.

Platí to obecně, TButton je jen vhodný kandidát.

Datum: 2024-06-27 15:02:00 Tagy: praxe

Praxe