Delphi-PRAXiS
Seite 2 von 2     12   

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi TList mit "verschiedenen Pointern" freigeben (https://www.delphipraxis.net/90813-tlist-mit-verschiedenen-pointern-freigeben.html)

SirThornberry 25. Apr 2007 16:39

Re: TList mit "verschiedenen Pointern" freigeben
 
wie bereits erwähnt könnten beide Recordtypen am Anfang des Records ein Feld haben welches den Typ angibt. Mit einem Cast auf einen der beiden Recordtypen kannst du dann prüfen welcher Typ tatsächlich in der Liste hängt.

Zum Vorschlag einfach
Delphi-Quellcode:
dispose(liste.Items[i])
zu verwenden:
Generell sollte das funktionieren. Allerdings habe ich gelesen (weiß nicht obs stimmt) das bei Records in denn Strings etc. enthalten sind von denen der Speicher nicht frei gegeben wird.

[Edit]
ich habs inzwischen mal "getestet".
Ohne Cast auf den Typ (dispose(liste.Items[i])) wird intern FreeMem aufgerufen
Mit Cast auf den Typ (dispose(PRecordTyp(liste.Items[i]))) wird intern Dispose aufgerufen

und dispose ruft intern Finalize auf was wiederum FinalizeArray aufruft was wohl dynamische Arrays und Strings frei gibt.
[/Edit]

3_of_8 25. Apr 2007 17:08

Re: TList mit "verschiedenen Pointern" freigeben
 
Wie kann denn FreeMem aufgerufen werden, wenn Dispose gar nicht "weiß", wie viel Speicher freigegeben werden darf?

sirius 25. Apr 2007 17:59

Re: TList mit "verschiedenen Pointern" freigeben
 
@Sir: Habs auch getestet und kann all deine Vermutungen bestätigen.

@3_of_8
Wenn der Compiler bei dispose einen untypisierten pointer (also list.items[i] : pointer) erkennt ruft er automatisch nur freemem auf. Vor jedem alloziierten Speicherplatz steht desen Größe (und noch ein bisschen mehr) Wenn du also mit Getmem 10 Bytes alloziierst, dann steht bei addr(list.items[i]-4) eine 10, wenn du einen string hast (z.B. s:='Hallo'), dann steht dort (bei addr(@s-4)eine 5), somit kann freemem, ohne Größenangabe speicher freigeben, denn die Größenangabe steht ja vor dem Datentyp (egal welcher, für arrays gilt dasgleiche)
Dort steht allerdings weder ne 10 noch ne 5. sondern an der Stelle sind mehrere Werte versteckt, aber mann kann es eineindeutig zurücktransformieren (zu 10 und 5)

Der angesprochene Unterschied, den Sir meinte, ist wenn ich dispose(PRecord1(list.items[i])) mache, dann ruft der Compiler auch tatsächlich dispose auf. Und Dispose ruft intern das angesprochene Finalize (etc. auf) und hinterher freemem. also ist der Unterschied nur, in dem finalize. Und ich habe gerade überprüft: Finalize gibt tatsächlch den Speicher von Arrays, strings, etc frei.
Nun, woher weis finalize, wo die strings im Record liegen? Versteckt übergibt der compiler bei dispose noch einen zweiten Parameter. Dies ist eine Adresse im Datensegment und beinhaltet die Struktur des Records. Und jetzt schließt sich der Kreis. Damit weis finalize, was und wo es noch strings, arrays, sonstige dynamische Variablen freigeben muss. Und zum zweiten ist es jetzt auch klar, warum wir den Typecast auf PRecord1 brauchen: Der Compiler muss ja auch wissen, welchen zweiten Parameter er an dispose übergeben muss.

Zusammenfassung:
aus dispose(list.items[i]) wird freemem(list.items[i])
aus dispose(PRecord1(list.items[i])) wird dispose(list.items[i],addr(Precord1Structure))


So, und jetzt noch eine neue Lösung für oben genanntes Problem:
Delphi-Quellcode:
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type Pp1=^Rp1;
     Rp1=record
       //typ ist für die wiedererkennung des Records
       typ:byte;
       //ab hier können jetzt statische und/oder dynamische Variablen folgen
       s:string;
     
     end;
type Pp2=^Rp2;
     Rp2=record
       //wir das obige Record
       typ:byte;
       s:array of integer;
       x:byte;
     end;
type
  TForm1 = class(TForm)
    Button1: TButton;
    procedure fill;
    procedure clear;
    procedure Button1Click(Sender: TObject);
  private
    { Private-Deklarationen }
    list:Tlist;
  public
    { Public-Deklarationen }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}


procedure Tform1.fill;
var p1:Pp1;
    p2:Pp2;
begin
  list:=Tlist.create;
  new(p1);
  p1^.typ:=1; //Typ zum wiedererkennen festlegen
  p1^.s:='Hallo';

  new(p2);
  p2^.typ:=2;
  setlength(p2^.s,2);
  p2^.s[0]:=10;
  p2^.s[1]:=20;

  list.add(p2);
  list.add(p1);

  new(p1);
  p1^.typ:=1;
  p1^.s:='';
  list.add(p1);

end;
procedure Tform1.clear;
var i:integer;
    typ:pbyte;
begin
  for i:=0 to list.Count-1 do begin
    typ:=list[i];
    case typ^of
      1: dispose(Pp1(list[i]));
      2: dispose(Pp2(list[i]));
      else raise Exception.CreateFmt('$d ist kein gültiger Recordtyp!',[typ^]);
    end;
  end;
  list.free;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  fill;
  clear;
end;

end.
Was bei allen tollen Funktionen auch der Compiler nicht schaffen wird, sind speicherbereiche freigeben, auf die ein untypisierter Pointer innerhalb des records zeigt

Mattze 29. Mai 2007 17:32

Re: TList mit "verschiedenen Pointern" freigeben
 
Hallo,

'tschuldigung. Ging jetzt eine Weile nicht bei mir!
Aber jetzt!
Vielen Dank für Eure Hilfe.
Inzwischen klappt es und natürlich klappt es so, wie es ja auch klappen muss - mit dispose.
Es war ein echt dummer gedanklicher Fehler von mir. Ich habe "die Reichweite von Assign" unlogisch hoch angesetzt.

Gruß
Mattze


Alle Zeitangaben in WEZ +1. Es ist jetzt 06:31 Uhr.
Seite 2 von 2     12   

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