Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   GUI-Design mit VCL / FireMonkey / Common Controls (https://www.delphipraxis.net/18-gui-design-mit-vcl-firemonkey-common-controls/)
-   -   Delphi Problem TStringlist.free (https://www.delphipraxis.net/59624-problem-tstringlist-free.html)

Master of the Wind 26. Dez 2005 09:44


Problem TStringlist.free
 
Liste der Anhänge anzeigen (Anzahl: 1)
Hallo,

ich muss leider nochmals mit der bitte an euch herantreten mir zu helfen. Ich habe ein Programm geschrieben, und wenn ich es beende kommt die Fehlermeldung ungültige Zeigeroperation. Der Compiler ist richtig eingestellt(Bereichsprüfung...). Der Fehler kommt genau an der markierten Stelle (Msglist.free, in dem destructor von TKonsole). Die Funktion Freeandnil hilft auch nix. Bitte schaut euch mal den Code an und helft mir bitte.



Ich bin über jede Antwort glücklich...Danke :thumb:

xaromz 26. Dez 2005 10:00

Re: Problem TStringlist.free
 
Hallo,

zwei Sachen vorneweg:

Erstens: Häng bitte Deinen Quellcode als Archiv an, so ist das etwas lang und zum Testen fehlt Dein Form.
Zweitens: Mir ist aufgefallen, dass Du einen Pointer auf eine Klasse übergibst (PKernel). Eine Klasse ist aber schon ein Pointer, das kannst Du Dir also sparen.

Ansonsten sehe ich beim Überfliegen gerade keinen Fehler, ich kann das Programm aber so nicht ausprobieren (siehe Erstens).

Gruß
xaromz

Muetze1 26. Dez 2005 10:24

Re: Problem TStringlist.free
 
Mir ist noch folgendes aufgefallen:

Delphi-Quellcode:
procedure TKernel.freeFunktionskette(address:PFunktionsglied);
begin
  if assigned(address) then
  begin
    if not (address^.danach=nil) then Funktionsketteabarbeiten(address^.danach);
    dispose(address);
  end;
end;
Solltest du nicht in dieser Funktion nicht freeFunktionskette(address^.danach); anstatt Funktionsketteabarbeiten(address^.danach); aufrufen?

Der Fehler tritt zwar bei der Freigabe der msglist auf, aber der Fehler kann durch anderen Code ausgelöst werden, der den Speicher von der msgList zerschiesst. Daher auch sowas wie hier aufgezeigt beachten und nachschauen. Ansonsten empfehle ich dir mal fastmm4 einzubinden und mal nachzuschauen, ob er dir nicht schon vorher Fehler meldet.

Master of the Wind 26. Dez 2005 10:34

Re: Problem TStringlist.free
 
danke...ein Fehler weniger, aber leider nicht der den ich meine, der Fehler ist immernoch da mit der Msglist... :wall: :gruebel: :cry:

xaromz 26. Dez 2005 10:34

Re: Problem TStringlist.free
 
Hallo,

ich hab mir mal selbst ein Form gebastelt (ist ja nichts weiter drauf), jetzt fehlen mir zum Testen noch ein paar Textdateien. Die hab ich einfach mal ignoriert und beim Beenden des Programms Beenden() aufgerufen; bei mir kommt da kein Fehler.

Eine Anmerkung hab ich noch: Du deklarierst alles Mögliche in einer Unit und verwendest diese sowohl in Deinem Hauptprogramm als auch in einer DLL. Insbesondere Dein Form solltest Du nicht in die DLL packen. Bau Dir eine weitere Klasse, die Du in Deinem Form erstellst und dann der DLL übergibst. Am Besten erstellst Du Dir ein Interface, das ist die sauberste Lösung. Im jetzigen Zustand kann man das nur als grausam bezeichnen :-D .

Gruß
xaromz

Master of the Wind 26. Dez 2005 10:38

Re: Problem TStringlist.free
 
Interface...hmm..damit kann ich leider nicht soviel anfangen, kannst du mir da eine Hilfe empfehlen...

xaromz 26. Dez 2005 16:12

Re: Problem TStringlist.free
 
Liste der Anhänge anzeigen (Anzahl: 1)
Hallo,

ich kenne leider kein gutes Tutorial für Interfaces. Aber ich versuche mal eine kleine Erklärung:

Interfaces sind im Grunde abstrakte Klassen. Sie beschreiben einen definierten Funktionsumfang einer Klasse. Hier mal ein Beispiel:
Delphi-Quellcode:
type
  IMyInterface = interface(IInterface)
  ['{7D30C89B-C144-420B-8F2C-501FEE4D787B}']
    function GetName: String;
    procedure SetName(const Value: String);
    procedure PrintName;
    property Name: String read GetName write SetName;
Wichtig ist: Ein Interface definiert keine Variablen. Folglich müssen alle Variablen über Properties mittels Getter und Setter definiert werden (siehe Name). Zusätzlich sollte ein Interface eine GUID haben, über die es eindeutig erkannt werden kann (['{...}']).

So wird ein Interface implementiert:
Delphi-Quellcode:
type
  TMyClass = class(TInterfacedObject, IMyInterface)
  private
    FName: String;
    function GetName: String;
    procedure SetName(const Value: String);
  public
    procedure MachWasAnderes;
    procedure PrintName;
    property Name: String read GetName write SetName;
  end;
Wichtig:
Alle Methoden, die im Interface definiert sind, müssen auch implementiert werden. Zusätzlich können noch beliebige weitere Methoden definiert werden.
Eine solche Klasse muss immer von TInterfacedObject abgeleitet werden, da dort einige Methoden definiert werden (z. B. Referenzählung, siehe unten).

Zur Benutzung:
Ein Interface besitzt einn Referenzzähler. Wenn dieser Null erreicht, zerstört sich das Objekt automatisch. Bei jeder Zuweisung einer Variablen wird der Referenzzähler automatisch erhöht. So weiß das Objekt, ob es noch benötigt wird. Dies hat einige Auswirkungen:
Interfaces sollten immer mit const übergeben werden:
Delphi-Quellcode:
procedure TuWas(const Intf: IInterface);
Interfaces sollten immer am Ende freigegeben werden, indem die Variable auf nil gesetzt wird:
Delphi-Quellcode:
procedure MachWas;
var
  Intf: IInterface;
begin
  Intf := CreateIrgendeinInterface;
  Intf.Blubber;
  intf := nil; <- Hier wird Intf freigegeben, da keine weitere Variable darauf zeigt
end;
Wenn ein Interface freigegeben wird, wird automatisch der Destructor des Objekts aufgerufen.

Da Interfaces sich selbst freigeben, sollte man immer darauf achten, am Ende des Programms sämtliche Referenzen zu entfernen, sonst erzeugt man ein Speicherleck.
Wenn eine Klasse, die ein Interface implementiert, einer Klassenreferenz zugewiesen wird, so wird der Referenzzähler nicht erhöht.

Nochmal mit obigem Beispiel zur Verdeutlichung:
Delphi-Quellcode:
procedure Eins;
var
  Obj: TMyClass;
  Intf: IMyInterface;
begin
  Obj := TMyClass.Create; // Referenzzähler = 0
  Obj.Name := 'Meier';
  Intf := Obj;            // Referenzzähler = 1 
  Intf.PrintName;
  Obj.MachWasAnderes;
  Intf := nil;            // Referenzzähler = 0 -> Objekt wird zerstört
  Obj.Free;               // Zugriffsfehler, Objekt ist schon zerstört
end;

procedure Zwei;
var
  Intf: IMyInterface;
begin
  Intf := TMyClass.Create; // Referenzzähler = 1;
  Intf.Name := 'Meier';
  Intf.PrintName;
  Intf.MachWasAnderes; <- Das geht nicht, MachWasAnderes ist in der Klasse definiert, nicht im interface
  Intf := nil;             // Referenzzähler = 0 -> Objekt wird zerstört
end;
Anhand dieses Beispiels sieht man, dass man Objekte und ihre Interfaces nicht mischen sollte.
Eine Möglichkeit, dieses Konstrukt trotzdem zum Laufen zu bekommen wäre, den Referenzzähler manuell zu erhöhen:
Delphi-Quellcode:
procedure EinsA;
var
  Obj: TMyClass;
  Intf: IMyInterface;
begin
  Obj := TMyClass.Create; // Referenzzähler = 0
  Obj._AddRef;            // Referenzzähler = 1
  Obj.Name := 'Meier';
  Intf := Obj;            // Referenzzähler = 2 
  Intf.PrintName;
  Obj.MachWasAnderes;
  Intf := nil;            // Referenzzähler = 1
  Obj.Free;               // Objekt wird zerstört
end;
Eine Sache noch:
Delphi-Quellcode:
procedure Drei;
var
  Intf1, Intf2: IMyInterface;
begin
  Intf1 := TMyClass.Create;
  Intf2 := Intf1;
  if (Intf1 = Intf2) then
    ShowMessage('Diese Meldung wird niemals erscheinen);
  Intf2 := nil;
  Intf1 := nil;
end;
Interfaces sind niemals identisch. ein Vergleich von Interfaces wird immer scheitern. Um dieses Problem zu beheben müsste jede erzeugte Klasse eine eindeutige ID erhalten, die über das Interface überprüft werden kann. Da verschiedene Interfaces das gleiche Objekt repräsentieren, wäre bei beiden Interfaces auch die ID gleich.

Was sind nun die Vorteile eines Interfaces?
Ein Interface ist sozusagen der Bauplan einer Klasse, den man benutzen kann, ohne die Klasse zu kennen. Das ist insbesondere bei DLLs interessant; eine DLL erzeugt ein Interface und das Hauptprogramm kann damit arbeiten, ohne dass der gesamte Klassen-Quellcode dem Hauptprogramm bekannt ist, da das Hauptprogramm das Interface kennt. Oder ein Hauptprogramm übergibt der DLL ein Interface, und die DLL kann damit arbeiten. Da die DLL nur das Interface kennt, bleibt diese schön klein.



Da ich heute etwas mit meinem neuen Delphi spielen wollte, habe ich mir erlaubt, Deinen Quellcode etwas zu überarbeiten.
Ich habe die einzelnen Klassen in eigene Units gesteckt und aus TKonsole ein Interface gebaut. Außerdem habe ich die Renderlogik aus dem Form genommen und in eine eigene Klasse (auch mit Interface) gesteckt. Programmlogik hat nämlich in einem Form nichts zu suchen, da gehört nur das Programminterface (Eingabe, Ausgabe) rein.
Da die beiden DLLs nur die Interfaces benötigen, sind sie viel kleiner geworden.
Schau Dir das Ganze mal an, vielleicht kanst Du damit ja was anfangen.

Ach ja, um die Anfangsfrage zu beantworten: Ein Fehler kommt bei mir nicht.

Gruß
xaromz

Master of the Wind 26. Dez 2005 19:10

Re: Problem TStringlist.free
 
erstmal vielen vielen dank, klasse:-D :thumb: :dancer: :hello: aber ein Problem hab ich gleich entdeckt. Die Tastureingabe wird nicht mehr angezeigt, weißt du gleich woran das liegt?

xaromz 26. Dez 2005 23:01

Re: Problem TStringlist.free
 
Hallo,

ja, ich hab vergessen, den FormKeyDown-Event zuzuweisen. Einfach im Objektinspektor wieder zuweisen.

Gruß
xaromz


Alle Zeitangaben in WEZ +1. Es ist jetzt 18:38 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