Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Programmieren allgemein (https://www.delphipraxis.net/40-programmieren-allgemein/)
-   -   Listen freigeben (https://www.delphipraxis.net/112173-listen-freigeben.html)

conti 16. Apr 2008 10:15


Listen freigeben
 
Hallo Leute,

ich arbeite gewöhnlich nicht mit Delphi; habe eine einfache Frage:
Wie werden Array und Listen korekt freigegeben in Delphi?

Reicht es wenn man nur die Liste selbst freigibt oder muss man auch alle Elemente der Liste separat freigeben?

DeddyH 16. Apr 2008 10:19

Re: Listen freigeben
 
Meine Hilfe sagt zu TList.Clear
Zitat:

Mit Clear wird das Array Items geleert, und Count sowie Capacity werden auf 0 gesetzt. Außerdem wird der gesamte vom Array belegte Speicher freigegeben.
Und dynamische Arrays gibst Du frei, indem Du mittels
Delphi-Quellcode:
SetLength(DeinArray,0);
die Größe auf 0 setzt.

Bbommel 16. Apr 2008 10:23

Re: Listen freigeben
 
Bei TList musst du dich selbst um das Freigeben der Elemente der Liste kümmern, die sich hinter den einzelnen Items verbergen. Eine Liste, die auch deren Speicher direkt mit freigibt, ist zum Beispiel TObjectList.

Bis denn
Bommel

DeddyH 16. Apr 2008 10:25

Re: Listen freigeben
 
Also stimmt mal wieder nicht, was in der Hilfe steht :?

[edit] :wiejetzt: Wo ist mein Text geblieben? [/edit]

Bbommel 16. Apr 2008 10:31

Re: Listen freigeben
 
Zitat:

Zitat von DeddyH
Also stimmt mal wieder nicht, was in der Hilfe steht :?

Doch, eigentlich schon. Der Speicher der Items (was ja letztlich ein Array von Zeigern ist) wird bei TList ja auch freigegeben. Nur: Diese Items zeigen ja bei den meisten Listen auf irgendwelche anderen Objekte und DEREN Speicher wird eben nicht freigegeben. Im Gegensatz dazu gibt TObjectList den Speicher sowohl der Zeiger aus der Liste wie auch den Speicher der Objekte, die sich dahinter verbergen, frei.

Zitat:

Zitat von DeddyH
[edit] :wiejetzt: Wo ist mein Text geblieben? [/edit]

Ich hab nix geklaut. ;)

Bis denn
Bommel

DeddyH 16. Apr 2008 10:46

Re: Listen freigeben
 
Noch mal zum Verständnis: angenommen, ich habe folgenden Typen definiert
Delphi-Quellcode:
type PMyRec = ^TMyRec;
TMyRec = record
  Feld1,
  Feld2: integer;
end;
Und nun befülle ich eine TList mit lauter PMyRecs. Was geschieht denn nun mit den Records beim Aufruf von Clear?

[edit] Hab gerade mal in den Sourcen von Delphi 5 nachgesehen. Es werden dort lediglich Count und Capacity auf 0 gesetzt.
Delphi-Quellcode:
procedure TList.SetCapacity(NewCapacity: Integer);
begin
  if (NewCapacity < FCount) or (NewCapacity > MaxListSize) then
    Error(@SListCapacityError, NewCapacity);
  if NewCapacity <> FCapacity then
  begin
    ReallocMem(FList, NewCapacity * SizeOf(Pointer));
    FCapacity := NewCapacity;
  end;
end;

procedure TList.SetCount(NewCount: Integer);
var
  I: Integer;
begin
  if (NewCount < 0) or (NewCount > MaxListSize) then
    Error(@SListCountError, NewCount);
  if NewCount > FCapacity then
    SetCapacity(NewCount);
  if NewCount > FCount then
    FillChar(FList^[FCount], (NewCount - FCount) * SizeOf(Pointer), 0)
  else
    for I := FCount - 1 downto NewCount do
      Delete(I);
  FCount := NewCount;
end;
Wenn ich das nun richtig verstehe, wird nur der Speicher, den die jeweiligen Zeiger verbrauchen, freigegeben. [/edit]

Bbommel 16. Apr 2008 10:51

Re: Listen freigeben
 
Ich selbst arbeite eigentlich fast immer mit Objekten, weniger mit records, daher die Antwort unter leichtem Vorbehalt, aber eigentlich: Mit denen passiert nix - will heißen: Sie bleiben ziemlich heimatlos im Speicher stehen. Wenn du die records beim Freigeben der Liste nicht selbst wieder entfernt, wirst du später auch ein Problem haben, da du dir mit der Liste ja auch sämtliche Pointer auf die Records gelöscht hast. Heißt: du kannst sie während des Programmlaufs gar nicht mehr freigeben.

Bis denn
Bommel

DeddyH 16. Apr 2008 10:54

Re: Listen freigeben
 
Überschnitten, hatte gerade editiert :lol:

Bbommel 16. Apr 2008 10:58

Re: Listen freigeben
 
Jau. :) Aber da ich deine Aussage ja eigentlich eh nur unterstützt habe, ist's ja nicht schlimm...

Für dein Beispiel müsstest du im Prinzip eine TRecordList erstellen und in deren Clear-Methode für alle Elemente der Liste ein Dispose aufrufen. Dann sollte es sauber sein.

Bis denn
Bommel

Viktorii 13. Nov 2008 08:56

Re: Listen freigeben
 
Nochmal zum mitschreiben: Also wenn ich mir das so erstelle:

Delphi-Quellcode:
  MyObjectList := TObjectList.Create();
und ich das so freigebe:

Delphi-Quellcode:
  MyObjectList.Clear;
  FreeAndNil(MyObjectList);
ist der komplette Speicher inklusive des Speichers der von den einzelnen Elementen/Objekten belegt wurde freigegeben?


Wenn ja:
Was ist wenn meine Elemente/Objekte in der ObjectList wiederum eine ObjectList enthält:
Delphi-Quellcode:
  TMyObject        = class
                        MyNumber     : Byte;
                        MyType       : Byte;
                        FriendsList  : TObjectList;        // for TFriendListItem  
                      end;

  TFriendListItem   = class
                        FriendNumber : byte;
                        constructor create (FriendNumber : Byte);
                      end;
Wird mit der oben genannten Methode auch der Speicher der ObjectList (bzw. der der Objekte der ObjectList) im Objekt der freizugebenden ObjectList freigegeben? :roteyes:
Ihr wisst was ich meine, oder :?:

DeddyH 13. Nov 2008 08:59

Re: Listen freigeben
 
TObjectList hat einen Parameter im Konstruktor mit Namen OwnsObjects (default true). Wenn Du den nicht auf false setzt, werden alle enthaltenen Objekte beim Zerstören freigegeben, das gilt auch für enthaltene weitere TObjectLists und deren Objekte.

Oreaden 13. Nov 2008 09:04

Re: Listen freigeben
 
Guten Morgen Viktorii,

für dein Problem, habe ich mal das Orakel befragt, es meinte

für die Freigabe reicht: FreeAndNil(MyObjectList); damit wird jeweils die Methode .Free der allokierten aufgerufen und anschließend die Liste selbst zerstört. Falls deine Objekte wiederrum Objekte enthalten, so müssen diese im jeweiligen Destruktor freigegeben werden.

Daher für deine Frage ein klares und eindeutiges Njan.

Schöne Grüße
Oreaden

Viktorii 13. Nov 2008 10:26

Re: Listen freigeben
 
@DeddyH: Okay, OwnsObjects habe ich auf true. Habe ich vergessen zu erwähnen.



Aber wer hat nun recht? DeddyH oder Oreaden bzw. das Orakel :?:

DeddyH 13. Nov 2008 10:30

Re: Listen freigeben
 
Probier' s doch mit FastMM aus ;)

Sir Rufo 13. Nov 2008 10:46

Re: Listen freigeben
 
Zitat:

Zitat von Viktorii
Aber wer hat nun recht? DeddyH oder Oreaden bzw. das Orakel :?:

öhhhm, behaupten beide etwas anderes? ... nein

Das Orakel weist nur darauf hin, dass die TObjectList die enthaltenen TObject's beim TObjectList.Free auch mit TObject.Free aus dem Speicher wirft.

Also wenn dieses Object an die TObjectList gehängt wird, dann ist beim TObjectList.Free alles aus dem Speicher.
Delphi-Quellcode:
TMyObject = class( TObject )
private
  FEinObject : TObject;
public
  constructor Create;
  destructor Destroy; override;
end;

constructor Create;
begin
  inherited;
  FEinObject := TObject.Create;
end;

destructor Destroy;
begin
  FEinObject.Free;
  inherited Destroy;
end;
Bei diesem Object funktioniert das nicht, was aber nicht an der Liste, sondern an dem Object selber liegt, denn das entfernt sich nicht sauber aus dem Speicher!
Delphi-Quellcode:
TMyObject = class( TObject )
private
  FEinObject : TObject;
public
  constructor Create;
end;

constructor Create;
begin
  inherited;
  FEinObject := TObject.Create;
end;
DIe TObjectList macht schon alles richtig, sie kann aber nicht zaubern!

cu

Oliver

Oreaden 13. Nov 2008 10:48

Re: Listen freigeben
 
:firejump: :firejump: Ein Schelm, wer dem Orakel nicht traut. Für die ungläubigen unter den Delphianern hier ein Testcode, möge jeder selbst seine Augen öffnen.

Delphi-Quellcode:
PROGRAM Project1;

{$APPTYPE CONSOLE}

USES
  SysUtils,
  Contnrs;

TYPE
  test = CLASS
    c: PChar;
  END;

  tTestList = CLASS(TObjectList)
    x: test;
    CONSTRUCTOR Create;
    //  Destructor Destroy; override;
  END;

  CONSTRUCTOR tTestList.Create;
  BEGIN
    x := test.Create;
  END;

  //destructor tTestList.Destroy;
  //begin
  // x.Free;
  // inherited;
  //end;

VAR
  x: tTestList;
BEGIN
  ReportMemoryLeaksOnShutdown := True;

  x := tTestlist.Create;
  x.Free;
END.

DeddyH 13. Nov 2008 11:24

Re: Listen freigeben
 
Ein Blick in die Contnrs.pas bringt Folgendes zu Tage:
Zitat:

Zitat von Contnrs.pas Delphi 5
Delphi-Quellcode:
procedure TObjectList.Notify(Ptr: Pointer; Action: TListNotification);
begin
  if OwnsObjects then
    if Action = lnDeleted then
      TObject(Ptr).Free;
  inherited Notify(Ptr, Action);
end;



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