Einzelnen Beitrag anzeigen

Benutzerbild von Codehunter
Codehunter

Registriert seit: 3. Jun 2003
Ort: Thüringen
2.272 Beiträge
 
Delphi 10.4 Sydney
 
#1

Zugriffsverletzung bei Zeiger auf statisches Array

  Alt 26. Aug 2019, 09:52
Hallo!

Ich versuche gerade, eine Klassenstruktur zu erfinden, die sich über ein statisches Array initialisieren lässt. Nur leider geht die Runtime nicht mit meiner Theorie konform und wirft eine AV.
Delphi-Quellcode:
unit Unit1;

interface

type
  TMyRecord = record
    A: Integer;
    B: Integer;
    C: Byte;
  end;

  TMyRecords = array of TMyRecord;
  PMyRecords = ^TMyRecords;

  TMyClass = class
  private
    FRecords: PMyRecords;
  protected
    function GetRecord(const AIndex: Integer): TMyRecord;
  public
    property Records[const AIndex: Integer]: TMyRecord read GetRecord; default;
  end;

  TMyClassA = class(TMyClass)
  strict private const
    RECS: array[0..1] of TMyRecord = (
      (A: 1; B: 2; C: 3),
      (A: 4; B: 5; C: 6)
    );
  public
    constructor Create;
  end;

  TMyClassB = class(TMyClass)
  strict private const
    RECS: array[0..1] of TMyRecord = (
      (A: 1; B: 2; C: 3),
      (A: 4; B: 5; C: 6),
      (A: 7; B: 8; C: 9)
    );
  public
    constructor Create;
  end;

implementation

{ TMyClass }

function TMyClass.GetRecord(const AIndex: Integer): TMyRecord;
begin
  Result := FRecords^[AIndex]; // <-- Hier die AV
end;

{ TMyClassA }

constructor TMyClassA.Create;
begin
  Records := @RECS;
end;

{ TMyClassB }

constructor TMyClassB.Create;
begin
  Records := @RECS;
end;

// ---------- Formular-Unit ---------

procedure TForm1.Button1Click(Sender: TObject);
var
  LClassA: TMyClassA;
begin
  LClassA := TMyClassA.Create;
  try
    ShowMessage(LClassA[1].A.ToString);
  finally
    FreeAndNil(LClassA);
  end;
end;

end.
Ich vermute mal, es kommt daher, dass ich hier TMyClass.FRecords als Zeiger auf ein dynamisches Array definiere und quasi als Platzhalter für ein statisches Array missbrauche.

In der Praxis ist die Array-Initialisierung um einiges komplexer. Bisher habe ich das über eine Klasse statt Record, ein TObjectList<TMyClass>, eine Schleife, ein case-Schleifenzähler-of und eine lange Codesequenz (ca. 670 Zeilen) gelöst. Mit den statischen Array-Initialisierungen im Klassenkopf dampft das Ganze auf 55 Zeilen ein, sollte weniger Laufzeit benötigen und ist sogar noch übersichtlicher.

Jetzt müsste nur noch die Runtime mitspielen

Grüße
Cody
Ich mache grundsätzlich keine Screenshots. Schießen auf Bildschirme gibt nämlich hässliche Pixelfehler und schadet der Gesundheit vom Kollegen gegenüber. I und E zu vertauschen hätte den selben negativen Effekt, würde aber eher dem Betriebsklima schaden
  Mit Zitat antworten Zitat