Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Programmieren allgemein (https://www.delphipraxis.net/40-programmieren-allgemein/)
-   -   Gibt TList.Delete darin befindliche Instanzen auch frei oder ? (https://www.delphipraxis.net/161871-gibt-tlist-delete-darin-befindliche-instanzen-auch-frei-oder.html)

die Suchende 25. Jul 2011 13:24

Gibt TList.Delete darin befindliche Instanzen auch frei oder ?
 
Hallo zusammen,

ich bin jetzt ein bischen mehr als zwei Jahre dabei (Delphi5) und das meiste funktioniert auch gut. Allerdings merke ich selbst, dass ich vieles nur so mache, dass es funktioniert ... der Stil ist noch nicht besonders gut und da habe ich mal eine Frage ...

Kurz noch vorne weg:
Wir lesen Daten aus einem Gerät aus (Datensatz ist "string") oder aus Dateien ein (Textdateien, ini, datensatz ist string). Ich arbeite also mit StringListen, wobei der erste "String" der StringList das Datum enthält und danach kommen die anderen Daten. Nun habe ich ja mehrere Datensätse also viele StringListen ... Da habe ich nun angefangen mit TList zu arbeiten. Die Liste aus Stringlisten lässt sich auch recht gut wieder auf der Oberfläche darstellen (TStringGrid).

Nun meine Frage, ob der folgende Code so korrekt ist - der Code ist ein bischen abgekürzt

Delphi-Quellcode:
procedure Dateneinlesen;
var List:   TList;
    strList: TStringList;
    i, j:   integer;
begin
  List := TList.Create;
  try

    //gehe Stringgrid durch und merke dir die alten Daten
    //     StringGrid hat Tabellenkopf
    //     Anzahl der Spalten ist der Anzahl "Datum + Daten im Datensatz" bereits angepasst
      for i:=1 to StringGrid.RowCount-1 do begin  
          strList := TStringList.Create;

          strList.add('0'); //alter Datensatz

          for j:=0 to StringGrid.ColCount-1 do begin
              strList.add(StringGrid.Cells[j,i]);
          end;

          List.Add(strList);
      end;

    //---------
    //neue Daten einlesen
    //     Datei öffnen
    ...

    //Daten einlesen
    repeat
      strList := TStringList.Create;

      strList.add('1'); //neue Daten

      strList.add(andere Daten);
 
      List.add(strList);
    until keine anderen Daten mehr

    //Datei schließen
    ...

    //--------
   
    //Liste nach Datum sortieren ... steht in allen Datensätzen natürlich an der gleichen Stelle
    //hier nicht weiter beschrieben
    ListeVonStrListenNachDatumSortieren(List,
               StrListSpalteDatum, BeginnInListe, EndeInListe);

    //Doppelte löschen
    ListeVonStrListenDatumDoppelteRaus(List, StrListSpalteDatum);

    //--------
    //Auf der OF anzeigen

    //    alte Daten aus StringGrid löschen
    StringGrid.RowCount := 2;
    for j:=0 to StringGrid.ColCount-1 do begin
        StringGrid.Cells[j,1] := '';
    end;

    //sortierte Daten ohne Doppelte eintragen
    for i:=0 to List.Count-1 do begin
        if StrinGrid.Cells[0,1] <> '' then StringGrid.RowCount := StringGrid.RowCount +1;

        strList := List.Item[i];
        for j:=1 to strList.Count-1 do begin
            //im ersten Element, steht nur, ob der Datensatz alt oder neu ist ... deshalb bei j=1 anfangen

            if j > StringGrid.ColCount-1 then begin
               StringGrid.Cells[j, i] := strList.Strings[j];
            end else begin
               breake; //was auch immer hier noch drin steht, was nicht drin stehen soll
            end;
        end;
    end;

  //--------
  finally
   for i:=0 to List.Count-1 do begin
       strList := List.item[i];
       strList.free;
   end;
   List.Free;

  end;
end;
Delphi-Quellcode:
procedure ListeVonStrListenDatumDoppelteRaus(List: TList;
                 StrListSpalteDatum: integer);
var strList1, strList2: TStringList;
    i:           integer;
begin
  if List.Count < 1 then exit;

  i:=0;
  repeat
      strList1 := List.Items[i];
      strList2 := List.Items[i+1];

      if (strList1.Count > 0) and (strList2.Count > 0) then begin
         if strList1.strings[StrListSpalteDatum] = strList2.strings[StrListSpalteDatum] then begin
           if strList1.strings[0] = '0' then begin
              strList1.free;
              List.Delete(i);
           end else begin
              strList2.free;
              List.Delete(i+1);
           end;
           //Doppelte dürfen/ können nicht da sein
           //Entweder das eine oder das andere ist falsch
         end else begin
           inc(i);
         end;
      end else begin
         inc(i); //sonst komm ich aus der Schleife nicht wieder raum
                 //aber, was sind das für komische Stringlisten
                 //      strList.Strings[0] = ob alt oder neu
                 //      strList.strings[strListSpalteDatum] = Datum
                 //      und Rest?
      end;
  until i >= List.Count-2;

  //nochmal letzten Beiden kontrollieren
  //kann nicht am Anfang der Schleife inc(i) machen, weil
  //     wenn ein Element/Item gelöscht wird soll er ja nicht hoch zählen
  //     -> am Ende nochmal kontrollieren
  strList1 := List.Items[List.Count-2];
  strList2 := List.Items[List.Count-1];
  if (strList1.Count > 0) and (strList2.Count > 0) then begin
     if strList1.strings[StrListSpalteDatum] = strList2.strings[StrListSpalteDatum] then begin
       if strList1.strings[0] = '0' then begin
          strList1.Free;
          List.Delete(List.Count-2);
       end else begin
          strList2.Free;
          List.Delete(List.Count-1);
       end;
     end;
  end;

end;
Was ist eigentlich, wenn man die StringListen, die in der List stecken, nicht frei gibt und nur List.free macht. Ist der speicher dann noch belegt, aber es zeigt nichts mehr darauf oder kann der Speicher dann wieder verwendet werden, aber es ist einfach schlechter Stil?
Oder muss ich das mit den StringList.free gar nicht machen? In der Hilfe steht nämlich:
"
Soll lediglich die Referenz auf ein Element gelöscht werden, ohne das Element selbst zu entfernen und den Wert von Count zu ändern, setzen Sie die Eigenschaft Items für Index auf nil.
"
Wenn ich mit List.Delete(i) eine Instanz=TstringList lösche, ist dann der Speicher wieder richtig freigegeben oder ist nur der Pointer gelöscht? Wenn ich zuvor schon die StringListe freigegeben habe, hat doch der Pointer gar nichts mehr auf das er in dem Moment zeigt? Oder ist dem Pointer das egal, weil er eh nur auf eine beliebige Adresse im Speicher zeigt?


Wenn euch noch weitere Fehler auffahlen, wäre ich über jede Korrektur sehr dankbar! Z.B. habe ich das Gefühl, dass die Tabelle (StringGrid) nich korrekt gelöscht wird, nur weil ban die Zeilenanzahl zurücksetzt... aber da das ein anderes Thema ist, wollte ich das hier nicht weiter ausmahlen.


Ich danke euch schon mal im Vorraus für den Support.
die Suchende

DeddyH 25. Jul 2011 13:28

AW: Gibt TList.Delete darin befindliche Instanzen auch frei oder ?
 
Das kannst Du recht einfach herausfinden, indem Du ReportMemoryLeaksOnShutdown auf true setzt. AFAIK gibt TList keine Instanzen frei, da seine Elemente vom Typ Pointer sind und nicht von TObject. Du kannst aber beispielsweise auf eine TObjectList ausweichen und deren Eigenschaft OwnsObjects auf true lassen(Voreinstellung), dann hast Du das gewünschte Verhalten.

schlecki 25. Jul 2011 13:54

AW: Gibt TList.Delete darin befindliche Instanzen auch frei oder ?
 
Zitat:

Zitat von DeddyH (Beitrag 1113453)
Das kannst Du recht einfach herausfinden, indem Du ReportMemoryLeaksOnShutdown auf true setzt. AFAIK gibt TList keine Instanzen frei, da seine Elemente vom Typ Pointer sind und nicht von TObject. Du kannst aber beispielsweise auf eine TObjectList ausweichen und deren Eigenschaft OwnsObjects auf true lassen(Voreinstellung), dann hast Du das gewünschte Verhalten.

Dafür muss man aber FastMM4 einbinden. In Delphi 5 ist das noch nicht eingebaut, iirc

himitsu 25. Jul 2011 14:24

AW: Gibt TList.Delete darin befindliche Instanzen auch frei oder ?
 
TList gibt nichts frei.
Es gibt es auch nicht umsonst die TObjectList, bei welcher man dann OwnsObjects auf true setzt, damit die Objekte freigegeben werden.

[edit] komisch, grade fehlten noch ein paar Beiträge :shock:
OK, also in Delphi 5 sieht es da wohl schlecht aus ... dort dußt du es also selber freigeben, bzw. du leitest dir die TObjectList ab und rüstest das OwnsObjects selber nach.

DeddyH 25. Jul 2011 17:10

AW: Gibt TList.Delete darin befindliche Instanzen auch frei oder ?
 
Das Delphi 5 habe ich glatt überlesen, obwohl es klar und deutlich da steht. Ist aber auch egal, dann lädt man es eben herunter und benutzt es dann (IIRC funktioniert FastMM auch schon unter D5, bin aber nicht zu 100% sicher).

jaenicke 25. Jul 2011 17:13

AW: Gibt TList.Delete darin befindliche Instanzen auch frei oder ?
 
Das geht sogar noch mit Delphi 4. ;-)

himitsu 25. Jul 2011 17:46

AW: Gibt TList.Delete darin befindliche Instanzen auch frei oder ?
 
Auch wenn FastMM einige Vorteile mitbringt (Speicherprüfung und vorallem daß dieser wesentlich schneller ist, als der alte DelphiMM),

aber verwirrt den armen Kerl doc nicht gleich. :zwinker:



Sein Problem lag ja eigentlich in der TList und da können wir so oder so zu 100% sagen, daß es nichts freigibt und das alte TObjectList noch nicht so otimal funktionierte.

Hatte die TObjektList damals eine Ereignismetode, für "Item wird gelöscht" ?
Wenn ja, dann könnte man diese ganz leicht benutzen und weg wäre das Problem.

die Suchende 25. Jul 2011 21:14

AW: Gibt TList.Delete darin befindliche Instanzen auch frei oder ?
 
Danke, dass ihr so schnell geantwortet hat.

wie es scheint habe ich ja soweit alles richtig gemacht, außer dass ich statt TList gleich TObjectList hätte verwenden können.

Ist "FastMM" eine Komponente? Was kann man damit machen? Ich kenn mich damit noch nicht so aus. Ich habe erst ein paar freie Komonenten mit reingeladen, z.B. um die Größe der Objecte auf der Oberfläche, wie TChart, StringGrid, Edits, Buttons usw. anzupassen, wenn man die Fenstergröße verändert.
Übrigens sagt ihr bei eurem Beitrag: http://www.delphipraxis.net/56271-fa...n-langsam.html
, dass es auch nicht besser ist als "der normale MemoryManager von Delphi", auch wenn ihn noch nicht wissentlich verwendet habe.

auf jeden Fall nochmal danke
die Suchende


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