AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Thema durchsuchen
Ansicht
Themen-Optionen

Warum gibt es hier eine Acess Violation?

Ein Thema von Benmik · begonnen am 8. Dez 2018 · letzter Beitrag vom 18. Dez 2018
Antwort Antwort
Seite 1 von 3  1 23      
Benmik

Registriert seit: 11. Apr 2009
560 Beiträge
 
Delphi 12 Athens
 
#1

Warum gibt es hier eine Acess Violation?

  Alt 8. Dez 2018, 00:03
In einem Modul deklariere ich:
Delphi-Quellcode:
type
  TDing = class(TObject)
    Nr: integer;
  end;
  TDingliste = class(TObjectList<TDing>)
  ...
  ...
  end;
In einem anderen Modul verwende ich das:
Delphi-Quellcode:
procedure Test;
var Dingliste:TDingliste;

  procedure Initialisiere;
  begin
    Dingliste := TDingliste.Create;
  end;

  procedure HierKnallts;
  var Ding:TDing;
  begin
    Ding := TDing.Create;
    Ding.Nr := 1;
    Dingliste.add(Ding); // Access Violation
  end;

begin
  Initialisiere;
  HierKnallts;
end;
Das verstehe ich nicht. Dingliste wird ordnungsgemäß erstellt und ist verfügbar. Nehme ich eine globale Variable für Dingliste, gibt es keine Probleme.

Geändert von Benmik ( 8. Dez 2018 um 01:04 Uhr) Grund: "begin" sollte schon da sein
  Mit Zitat antworten Zitat
Schokohase
(Gast)

n/a Beiträge
 
#2

AW: Warum gibt es hier eine Acess Violation?

  Alt 8. Dez 2018, 00:17
Also mit 10.3 Rio kann ich nichts feststellen, da gibt es keine Exception.
  Mit Zitat antworten Zitat
Benmik

Registriert seit: 11. Apr 2009
560 Beiträge
 
Delphi 12 Athens
 
#3

AW: Warum gibt es hier eine Acess Violation?

  Alt 8. Dez 2018, 00:38
Habe ich auch grad mal nachgebastelt, bei mir auch nicht. Dürfte ja auch gar nicht sein.
Woran könnte das theoretisch liegen?
  Mit Zitat antworten Zitat
Schokohase
(Gast)

n/a Beiträge
 
#4

AW: Warum gibt es hier eine Acess Violation?

  Alt 8. Dez 2018, 00:46
Beliebt ist Ding.Create statt TDing.Create
  Mit Zitat antworten Zitat
Benmik

Registriert seit: 11. Apr 2009
560 Beiträge
 
Delphi 12 Athens
 
#5

AW: Warum gibt es hier eine Acess Violation?

  Alt 8. Dez 2018, 01:04
Oouuh, jetzt fällt mir eine mögliche Antwort selber ein.

Die Routine "HierKnallts" ist eine Callback-Routine, deren aufrufende Routine von einer weiteren Unterprozedur von "Test" aufgerufen und mit @HierKnallts übergeben wird.
Obwohl man im Debugger die Variable ohne weiteres sieht, erinnere ich mich, dass es da mit der Sichtbarkeit Probleme gab. Daher funktioniert auch die globale Variable.
  Mit Zitat antworten Zitat
Benutzerbild von jaenicke
jaenicke

Registriert seit: 10. Jun 2003
Ort: Berlin
9.648 Beiträge
 
Delphi 11 Alexandria
 
#6

AW: Warum gibt es hier eine Acess Violation?

  Alt 8. Dez 2018, 02:29
Ich kann nur den Rat geben niemals Variablen oberhalb von Unterroutinen einer Methode zu deklarieren. Das führt nur zu Konfusionen. Man sollte die benötigten Variablen an Unterroutinen immer direkt mitgeben.

Sprich statt:
Delphi-Quellcode:
procedure Test;
var
  Dingliste:TDingliste;

  procedure HierKnallts;
  begin
    Dingliste.add(Ding); // Access Violation
  end;

begin
  ...
  HierKnallts;
end;
Besser:
Delphi-Quellcode:
procedure Test;

  procedure HierKnallts(ADingliste: TDingliste);
  begin
    ADingliste.add(Ding);
  end;

var
  Dingliste: TDingliste;
begin
  ...
  HierKnallts(Dingliste);
end;
So kann man viel leichter debuggen was da wo schief geht...

Die Routine "HierKnallts" ist eine Callback-Routine, deren aufrufende Routine von einer weiteren Unterprozedur von "Test" aufgerufen und mit @HierKnallts übergeben wird.
Obwohl man im Debugger die Variable ohne weiteres sieht, erinnere ich mich, dass es da mit der Sichtbarkeit Probleme gab. Daher funktioniert auch die globale Variable.
Wenn es Probleme mit der Sichtbarkeit gäbe, würde es nicht kompilieren. Alles andere was mit Sichtbarkeit zu tun hat, würde nur zu dem Problem führen, wenn es irgendwo eine zweite gleichnamige Variable geben würde.
Sebastian Jänicke
AppCentral
  Mit Zitat antworten Zitat
8. Dez 2018, 06:29
Dieses Thema wurde am "08. Dec 2018, 06:29 Uhr" von "Luckie" aus dem Forum "Algorithmen, Datenstrukturen und Klassendesign" in das Forum "Object-Pascal / Delphi-Language" verschoben.
hoika

Registriert seit: 5. Jul 2006
Ort: Magdeburg
8.276 Beiträge
 
Delphi 10.4 Sydney
 
#8

AW: Warum gibt es hier eine Acess Violation?

  Alt 8. Dez 2018, 07:12
Hallo,
dein Code ist bestimmt nur dem richtigen Code nachgestellt. .?
Ichbdenke, Du hast die Listenvariable doppelt deklariert.
Heiko
  Mit Zitat antworten Zitat
Benutzerbild von Uwe Raabe
Uwe Raabe

Registriert seit: 20. Jan 2006
Ort: Lübbecke
11.475 Beiträge
 
Delphi 12 Athens
 
#9

AW: Warum gibt es hier eine Acess Violation?

  Alt 8. Dez 2018, 09:30
Man sollte die benötigten Variablen an Unterroutinen immer direkt mitgeben.
Das macht es auch wesentlich einfacher diese Unterroutinen in eigene Methoden zu extrahieren.
Uwe Raabe
Certified Delphi Master Developer
Embarcadero MVP
Blog: The Art of Delphi Programming
  Mit Zitat antworten Zitat
Benmik

Registriert seit: 11. Apr 2009
560 Beiträge
 
Delphi 12 Athens
 
#10

AW: Warum gibt es hier eine Acess Violation?

  Alt 8. Dez 2018, 10:07
@jaenicke
Dein Ratschlag ist sicher analog zu dem, wenn irgend möglich keine globalen Variablen zu verwenden. Dingliste wäre dann praktisch eine globale Variable für die Unterroutinen von "Test". Es ist aber doch auch so, dass dies ein Design-Ratschlag ist und keinerlei technische Nachteile hat? (Delphi lässt ja diese Konstruktion explizit zu!)

@Uwe Raabe: Könntest du das kurz erläutern?

Ich wäre dankbar, wenn ich dieses Phänomen, das ich eigentlich kenne, mal verstehen würde.

Um etwas auszuholen: Gerade um meinen Code übersichtlich zu halten, teile ich ihn in möglichst viele einzelne Aufgaben auf. Eigentlich ist das gute Programmierpraxis; es gibt einen Guru, der gefordert hat, eine Routine dürfe immer nur eine einzige Aufgabe erledigen; ich habe ihn mal bei Wikipedia nachgeschlagen, leider aber seinen Namen vergessen und ich finde ihn auf die Schnelle auch nicht wieder.

Wenn ich mir professionellen Code anschaue, dann habe ich noch nie verstanden, warum diese Jungs sich oft einen Sch... um dieses Prinzip kümmern. Ellenlange Routinen, möglichst noch nach den Delphi Style Guides, was den Text noch doppelt so lang macht. Eine Qual, das zu debuggen. Ebenfalls eine Qual ist es, wenn die Aufgaben zwar in Unterroutinen zerlegt wurden, aber jede Routine einzeln bzw. eine eigene Methode ist. Man springt beim Debuggen dann zu zahllosen Stellen im Code hin und her.

Ich zerlege daher die Aufgaben einer Routine in Einzelteile. Und wenn diese Aufgaben nur einmal im ganzen Code vorkommen (oft 90%), dann verlege ich sie in eine Unterroutine und gebe ihr einen aussagekräftigen Namen, bei dem Aussagekraft vor (englischer) Kürze geht. So verstehe ich auch nach Monaten und Jahren noch, was da passiert. Kein Wunder, dass meine absolute Lieblingsneuerung damals Code Folding war! Wenn möglich, besteht meine Hauptroutine nur aus den Namen der 10 Unterprozeduren. Dank Ctrl+Shift-K-P liegt das ganze Gebilde kompakt vor mir. Daher würde ich jaenickes Ratschlag auch nur äußerst ungern folgen, denn so kann ich den Weg einer Variablen durch die Unterprozeduren leicht verfolgen. Mit F8 gehe ich durch die 10 Zeilen mit den Namen der Unterprozeduren und sehe viel leichter, wo etwas geschieht, was ich nicht beabsichtigt habe.

OK, nun zur Sache. Auch im besagten Beispiel handelt es sich um eine Klassenmethode mit mehreren Unterroutinen. Das Original von "Test" ist eine Unterprozedur dieser Klassenmethode und heißt FindeDateien(VerzListe[i],'*',False,@FindeDateiRM,Abbrechen); . Sie ruft procedure FindeDateien(const BasisVerz,DateiMaske:string;MitUVerz:Boolean;FindeDateienRM:TFindeDateienRM;var Abbruch:Boolean); auf, das in einer anderen Unit liegt, keine Klassenmethode ist und die Callback-Routine procedure FindeDateiRM(const BasisVerz:string;const Data:TWin32FindDataW;var Abbrechen:Boolean); aufruft, die ebenfalls eine Unterroutine der Klassenmethode ist. In FindeDateiRM wird eine Instanz von TBld erzeugt, die Dateieigenschaften von TWin32FindDataW eingefüllt und die Instanz dann zur Objektliste TObjectList<TBld> hinzugefügt.

Also so:

In einem anderen Modul:
Delphi-Quellcode:
type
TFindeDateienRM = procedure(const Verzname:string;const Data:_WIN32_FIND_DATAW;var Abbr:Boolean); stdcall;

procedure FindeDateien(const BasisVerz,DateiMaske:string;MitUVerz:Boolean;FindeDateienRM:TFindeDateienRM;var Abbruch:Boolean);
Delphi-Quellcode:
procedure TForm1.ErstelleListe;
var Bldliste:TBldliste;
begin

  procedure Intialisiere;
  begin
    Bldliste := TBldliste.Create(True);
  end;

  procedure FindeDateiRM(const BasisVerz:string;const Data:TWin32FindDataW;var Abbrechen:Boolean);
  var Bld:TBld;
  begin
    Bld := TBld.Create;
    Bld.Name := string(Data.cFileName);
    Bldliste.add(Bld); // Das will er nicht
  end;

  procedure ListeDateienAuf;
  begin
    FindeDateien(VerzListe[i],'*',False,@FindeDateiRM,Abbrechen);
  end;

end;
Hier kommt es zu dem geschilderten Phänomen. Die TObjectList ist bei der Klassenmethode deklariert und im Debugger in allen Unterprozeduren sichtbar. Trotzdem kommt es zu einer Schutzverletzung, wenn ich keine globale Variable verwende. Was genau geschieht da?
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 1 von 3  1 23      

 

Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 19:03 Uhr.
Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz