![]() |
AW: Zugriff auf procedure und funktionen nicht instanziierter Klassen / Objekte
Zitat:
Delphi-Quellcode:
TTest = class(TObject) private FTestProperty: Integer; public procedure DoSomething; function DoAnything: Integer; property TestProperty: Integer read FTestProperty write FTestProperty; end; function TTest.DoAnything: Integer; begin result := FTestProperty + 1; end; procedure TTest.DoSomething; begin ShowMessage('Hallo Welt'); end; procedure TForm1.Button1Click(Sender: TObject); var Test: TTest; begin Test.DoSomething; Test.TestProperty := 10; ShowMessage(IntToStr(Test.DoAnything)); end; Und jetzt das Entscheidende: Schalte die Optimierung von Delphi aus! Sonst bekommst Du erst am Ende einen Zugriffsfehler! |
AW: Zugriff auf procedure und funktionen nicht instanziierter Klassen / Objekte
Klar geht das. Eine Methode ist eben auch nur Code.
Sicher, es ist böse und risikoreich - aber es lassen sich eben auch schlechte Programme compilieren. Mit ein bisschen Glück bekommst du aber eine Warning in der sowas steht wie "Zugriff auf nicht initialisierte Variable" oder so. Falls du natürlich auf Daten der Klasse zugreifst ist das noch viel böser und fliegt dir im besten Falle sofort mit einer AV um die Ohren :P |
AW: Zugriff auf procedure und funktionen nicht instanziierter Klassen / Objekte
Zitat:
Zitat:
interessant wird es umso mehr, wenn man klassen weiterentwickelt. so habe ich zB in der vergangenheit manchmal klassenvariablen zu properties verändert, um eine nachträgliche vererbung zu implementieren.
Delphi-Quellcode:
zB: TMyClassNew und TMyClassOld implementieren beide ein und dasselbe Interface.
class Base=class FistVersionVar : TMyClass; end; //alte version class BaseV1=class(Base) property FirstVersionVar : TMyClassOld read FGetMyClass; end; class BaseV2=class(Base) property FirstVersionVar : TMyClassNew read FGetMyClass; end; Zitat:
was ändert das muß ich jetzt fragen? erhalte ich dann einen anderen stack trace/ die AV an einer anderen stelle? |
AW: Zugriff auf procedure und funktionen nicht instanziierter Klassen / Objekte
Zitat:
Zitat:
|
AW: Zugriff auf procedure und funktionen nicht instanziierter Klassen / Objekte
Der Hintergrund ist folgender: Der Code jeder Klasse besteht immer. Eine Klasse ist im Speicher nichts weiter, als ein Stück Feld-Definitionen für den Fall der Instanziierung, und ein Stück, in dem alle Methoden inkl. deren Code steht. Eine Instanz bekommt NICHT je ihre ganz eigene Kopie des Codes, sondern verweist immer nur auf die Speicherstelle, an der die Klassendefinition sie stehen hat. (Bzw. die jeweilige Elternklasse, oder es wird die VMT bemüht wenn es um virtuelle Methoden geht.) Der Code ist ab Programmstart einfach IMMER da. Die Felder auf die ggf. zugegriffen wird, sind es jedoch nicht.
Weist man also einer Variablen eine Instanz zu und zerstört diese ohne "nillen", so hat man wunderbar nachher Zugriff auf die Methoden, selbst wenn der Speicher der Instanz längst überschrieben wurde. Der Compiler weiss ja von welchem Typ die Referenz ist, und verweist munter auf die jeweiligen Stellen im Code-Segment, völlig egal ob da eine Instanz ist oder nicht. Technisch gesehen ist dies sogar nichtmals ein Fehler, da die Methoden ja da sind! Da man (der Compiler) nicht immer 100%ig wissen kann, ob in diesen auf Felder zugegriffen wird, die möglicherweise nicht existieren, geht das auch durch den Compiler. Im günstigsten Fall mit Warnung, aber an und für sich ist da aus technischer Sicht nichts falsch dran. Man muss halt aufpassen. Und ja, das ist in anderen Sprachen auch so, wenn gleich einige solche Dinge besser erkennen können, und ggf. gleich ganz die Kompilierung untersagen. Zwingend ist das nicht. Statische Methoden sind unter der Haube fast mit "normalen" identisch. Hier sagt man dem Compiler nur explizit: Wenn das hier aufgerufen wird, stelle mir bitte sicher, dass ich nur auf Dinge zugreife, die bereits mit der nackten Klassendeklaration in Existenz gerufen wurden! (Also andere statische Methoden für die das sicher gestellt wurde, und Klassenvariablen.) (Zudem lassen diese sich dann über den Namespace der Klasse aufrufen, nicht (nur) über eine Instanz-Referenz.) Ansonsten stehen die genau so im Codesegment wie alles andere auch. (Und, Spezialfall Delphi, "self" wird anders behandelt.) TL;DR: Der Code ist immer da, und steht genau ein Mal pro Klasse im Speicher (egal wie viele Instanzen). Er wird immer nur von dieser einen Stelle aus aufgerufen, der Compiler ist dafür verantwortlich. Eine Instanz braucht es für den blanken Aufruf nicht, der Code ist schließlich vorhanden. Manche Sprachen prüfen sowas strikter ab, es ist aber nur ein formaler/semantischer Fehler - kein technischer/syntaktischer. Manche stellen sowas in die Verantwortung des Programmierers (und warnen ggf.), andere versuchen das ganz zu unterbinden (wodurch manche Hacks allerdings auch unmöglich werden). Delphi gehört zu ersterem, und das ist völlig in Ordnung. |
AW: Zugriff auf procedure und funktionen nicht instanziierter Klassen / Objekte
Man muss eben wissen, das Delphi nicht das Modernste an Programmiersprache ist, was es auf der Welt gibt. Da kommt sowas schon mal vor.
Abhilfe: 1. Ordentlich programmieren (Erzeugerprinzip verwenden, d.h. wer instantiiert, gibt auch frei) 2. Unit-Tests 3. FastMem einbauen Nicht instantiierte Objekte hatte ich sehr selten (z.B. wenn ein Objekt per Message weitergeleitet wird und nicht klar ist, wie lange es lebt). Aber das ist ja auch ein Verstoß gegen (1) Ich glaube, FastMem findet die Fehler, bei denen ein nicht instantiiertes Objekt verwendet wird. |
AW: Zugriff auf procedure und funktionen nicht instanziierter Klassen / Objekte
hm... technisch ist klar, was wie wo und warum.
andererseits ist mir jetzt auch klar, wieso ich noch nie eine (komplexere) delphi anwendung ohne AV gesehen habe, selbst die IDE immermal knallt mit den sinnlosesten fehlermeldungen von den blödsinnigsten units/zeilen etc. :P 1) was mich jetzt noch mal interessiert ist, wie dann eigentlich proceduren implementiert sind, welche auf (windows-) messages reagieren (zB Painter). da der code ja immer vorhanden ist, unabhängig der klasseninstanz, muß ja irgendwo geregelt werden, welche instanz nun die message erhält, und welche nicht. ist es theoretisch vorstellbar, das eine nil-klasse eine message (zB wm_paint) erhält? 2) was ändern FastMem bzw. die Code Optimierung an dem ganzen? |
AW: Zugriff auf procedure und funktionen nicht instanziierter Klassen / Objekte
Zitat:
Zitat:
Zitat:
Dir fehlen entscheidende Grundlagen, um hier mitreden bzw. kritisieren zu können. Schreib einfach saubere Programme, das ist schon schwer genug. |
AW: Zugriff auf procedure und funktionen nicht instanziierter Klassen / Objekte
Zitat:
Delphi-Quellcode:
an das jeweilige Form geschickt.
Form.Dispatch
Delphi-Quellcode:
ist in
Dispatch
Delphi-Quellcode:
deklariert und sucht sich an Hand der Nachrichtentabelle des Objekts die passend
TObject
Delphi-Quellcode:
Methode raus oder ruft, falls es keine gibt, die virtuelle Methode
message
Delphi-Quellcode:
auf.
DefaultHandler
Rein theoretisch sollte das auch mit einer ungültigen Instanz funktionieren, aber wie jeder Hack ist diese Angabe ohne Gewähr. Gruß, Sven |
AW: Zugriff auf procedure und funktionen nicht instanziierter Klassen / Objekte
Liste der Anhänge anzeigen (Anzahl: 1)
erstmal danke für die antworten.
im Anhang habe ich mal ein bsp für einen StackTrace eines Fehlers angehangen, welchen ich derzeit provozieren kann, indem ich im start einer anwendung sofort ein Terminate einbringe (mittels timer, ich bin zufällig auf den effekt gestossen). Offensichtlich wird hier die hälfte der anwendung freigegeben, dann eine Message bearbeitet (wm_killfocus). Die Komponenten dürften bekannt sein, sodass vermutungen wie Spagetticode ausgeschlossen werden können. (DevExpress) Wie man sieht: keine einzige Zeile eigener Quellcode. (oder eben schon entladen) Ich habe jetzt mal grob die DevExpress quellen überflogen (eigentlich keine Zeit diese tage für solche Spielereien) und darin enthalten sind mehrere globale VariablenInstanzen, etc pp. da der Stacktrace durchklappert bis zum ersten Zugriff auf ein Klassenfeld, kann ich jetzt rätselraten, ob die vorherigen objekte nun instanziiert sind, oder der code zufällig so aufgebaut ist, das bis zuletzt nicht auf felder zugegriffen wird. Zitat:
Zitat:
Da man bei solchen Fehlern wie zB den oben von Entwicklern idR hört "da war irgendwas nicht instanziiiert" und "das ist nicht nachvollziehbar" (ist ja auch so, wir haben das bei paar Hunder Anwendern bei manchen paar mal die Woche (alle 2-3 Tage), bei teilweise 24*7 Betriebsdauer der Software {Verwaltungssoftware Unternehmenssteuerung}), beschäftige ich mich derzeit halt doch mal wieder mit solchen dingen, da ich eher sehe wie Anwender eine Software bedienen und somit teilweise besser Rückschlüsse auf technische Abläufe/Zusammenhänge ziehen kann. Es geht ja zB schon damit los, das es für viele Bediener nur Doppelclick gibt, einfach klick gibt es nicht. (daher haben wir mit vielen manwochen aufwand alle Application.processmessages ersetzt, da liegen ordner auf der tastatur während es rechnet, es werden zufällige tasten gedrückt, zum schluß kilbert es, da die anwendung irgendwelche eingaben verarbeitet hat) Letzendlich ist die Frage, wie man in solchen Fällen von zufälligen Fehlern, welche meist im Stacktrace auf Codezeilen verweisen die nicht mal in den eigenen Bibliotheken liegen ein Debugging/Eingrenzung vornimmt. Zitat:
|
Alle Zeitangaben in WEZ +1. Es ist jetzt 14:41 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