Einzelnen Beitrag anzeigen

Benutzerbild von sirius
sirius

Registriert seit: 3. Jan 2007
Ort: Dresden
3.443 Beiträge
 
Delphi 7 Enterprise
 
#13

Re: TList mit "verschiedenen Pointern" freigeben

  Alt 25. Apr 2007, 18:59
@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
Dieser Beitrag ist für Jugendliche unter 18 Jahren nicht geeignet.
  Mit Zitat antworten Zitat