![]() |
Zugriffsverletzung bei Zeiger auf statisches Array
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:
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.
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. 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 |
AW: Zugriffsverletzung bei Zeiger auf statisches Array
Ein einfacher Trick um die unterschiedlichen Arraytypen anzugleichen ist die Deklaration so zu ändern:
Delphi-Quellcode:
type
TMyRecords = array[0..100] of TMyRecord; |
AW: Zugriffsverletzung bei Zeiger auf statisches Array
Delphi-Quellcode:
Aber nur wenn du versprichst, dass TMyRecord keine referenzgezählten Typen verwendet.
unit Codehunter.View;
interface uses Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls; type TForm1 = class(TForm) Button1: TButton; procedure Button1Click(Sender: TObject); private { Private declarations } public { Public declarations } end; type TMyRecord = record A: Integer; B: Integer; C: Byte; end; TMyRecords = array of TMyRecord; PMyRecords = ^TMyRecords; TMyClass = class private FRecords: TMyRecords; 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..2] of TMyRecord = ( (A: 1; B: 2; C: 3), (A: 4; B: 5; C: 6), (A: 7; B: 8; C: 9) ); public constructor Create; end; var Form1: TForm1; implementation {$R *.dfm} { TMyClass } function TMyClass.GetRecord(const AIndex: Integer): TMyRecord; begin Result := FRecords[AIndex]; end; { TMyClassA } constructor TMyClassA.Create; var I: Integer; begin System.SetLength(FRecords, Length(RECS)); for I := System.Low(RECS) to System.High(RECS) do System.Move(RECS[I], FRecords[I], SizeOf(RECS[I])); end; { TMyClassB } constructor TMyClassB.Create; var I: Integer; begin System.SetLength(FRecords, Length(RECS)); for I := System.Low(RECS) to System.High(RECS) do System.Move(RECS[I], FRecords[I], SizeOf(RECS[I])); end; procedure TForm1.Button1Click(Sender: TObject); var LClassA: TMyClassA; begin LClassA := TMyClassA.Create; try ShowMessage(LClassA[1].A.ToString); finally LClassA.Free; end; end; end. Okay sind ordinale Typen (Byte, Integer, Cardinal, Int64). Pfui alles andere (string, Interface, dynamisches Array). |
AW: Zugriffsverletzung bei Zeiger auf statisches Array
Deklarier TMyRecords mal so:
Delphi-Quellcode:
TMyRecords = Array[0..0] of TMyRecord;
|
AW: Zugriffsverletzung bei Zeiger auf statisches Array
Zitat:
Zitat:
Zitat:
Delphi-Quellcode:
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) ); //<-- "Anzahl der Elemente (3) weicht von der Deklaration (2) ab" |
AW: Zugriffsverletzung bei Zeiger auf statisches Array
Zitat:
Eventuell hilft dieser Ansatz bei deinem Problem:
Delphi-Quellcode:
unit Unit455;
interface type TMyRecord = record A: Integer; B: Integer; C: Byte; end; TMyRecords = TArray<TMyRecord>; type TMyClass = class private FRecords: TMyRecords; protected function GetRecord(const AIndex: Integer): TMyRecord; procedure InitRecords(const Source: array of 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..2] 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 uses System.Generics.Collections; { TMyClass } function TMyClass.GetRecord(const AIndex: Integer): TMyRecord; begin Result := FRecords[AIndex]; end; procedure TMyClass.InitRecords(const Source: array of TMyRecord); begin SetLength(FRecords, Length(Source)); TArray.Copy<TMyRecord>(Source, FRecords, Length(Source)); end; { TMyClassA } constructor TMyClassA.Create; begin InitRecords(Recs); end; { TMyClassB } constructor TMyClassB.Create; begin InitRecords(Recs); end; end. |
AW: Zugriffsverletzung bei Zeiger auf statisches Array
@Uwe: Perfekt! So gehts. An generische Arrays hatte ich auch schon gedacht, bekam dann aber auch da nicht die generischen mit den statischen übereinander. Dass es eine statische Copy-Methode gibt war mir gar nicht bewusst. So müsste das doch eigentlich sogar dann funktionieren, wenn im Record ein String-Element vorkommt, oder?
@TiGü und Neutral General: Der Compilerfehler mit der Elementanzahl war eigene Blödheit, ich hatte (natürlich) auch per Copy&Paste vergessen, die Elementanzahl zu ändern. Aber Uwes Lösung passt am besten, weil ich dann die Objektorientierung am besten einhalten kann. |
AW: Zugriffsverletzung bei Zeiger auf statisches Array
Versuch es mal so:
Delphi-Quellcode:
Geht natürlich schief wenn nichts im Array ist.
TMyRecords = array of TMyRecord;
PMyRecords = ^TMyRecords[0]; Gruß K-H |
AW: Zugriffsverletzung bei Zeiger auf statisches Array
Warum nicht klassisch objektorientiert, ganz ohne hässliche Pointer?
Code:
Und so kannst Du auch die Übergabeparameter noch prüfen.unit Unit1; interface type TMyRecord = record A: Integer; B: Integer; C: Byte; end; TMyClass = class private protected function GetRecord(const AIndex: Integer): TMyRecord; virtual; abstract; 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) ); protected function GetRecord(const AIndex: Integer): TMyRecord; override; public end; TMyClassB = class(TMyClass) strict private const RECS: array[0..2] of TMyRecord = ( (A: 1; B: 2; C: 3), (A: 4; B: 5; C: 6), (A: 7; B: 8; C: 9) ); protected function GetRecord(const AIndex: Integer): TMyRecord; override; end; implementation function TMyClassA.GetRecord(const AIndex: Integer): TMyRecord; begin result := Recs[AIndex]; end; function TMyClassB.GetRecord(const AIndex: Integer): TMyRecord; begin result := Recs[AIndex]; end; end. |
Alle Zeitangaben in WEZ +1. Es ist jetzt 01:16 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz