2009-06-19 30 views
2

Unten habe ich einen Code eingefügt, der von Ray Konopka (Teil der Cogerage-Präsentation) geschrieben wurde. Ich plane, es zu benutzen, jedoch bin ich nicht sicher, wie man (in der Fliege) mehrfache Gegenstände säubert. Alle meine Versuche waren nicht gut und gerendert Speicherverlust. Irgendwelche Gedanken werden geschätzt. Danke,Mehrere Objekte in Delphi freigeben

program stringlistDictionary; 

{$APPTYPE CONSOLE} 

uses 
Classes, 
SysUtils; 

type 
    TPlayer = class 
    public 
    Name: string; 
    Position: string; 
    Hits: Integer; 
    AtBats: Integer; 
    constructor Create(Name, Position: string); 
end; 


    constructor TPlayer.Create(Name, Position: string); 
    begin 
     inherited Create; 
     Self.Name := Name; 
     Self.Position := Position; 
     Hits := 0; 
     AtBats := 0; 
    end; 


    var 
     Team: TStringList; 
     Player, NewPlayer: TPlayer; 
     I: Integer; 


    function FindPlayer(const Name: string): TPlayer; 
    var 
     Idx: Integer; 
    begin 
     Result := nil; 
     if Team.Find(Name, Idx) then 
     Result := TPlayer(Team.Objects[ Idx ]); 
    end; 


    begin {== Main ==} 

     Writeln('StringList Dictionary'); 
     Writeln('---------------------'); 
     Writeln; 

     Team := TStringList.Create; 
     try 
     NewPlayer := TPlayer.Create('Aramis Ramerez', 'Third Base'); 
     NewPlayer.Hits := 120; 
     NewPlayer.AtBats := 350; 

     Team.AddObject(NewPlayer.Name, NewPlayer); 

     NewPlayer := TPlayer.Create('Derrick Lee', 'First Base'); 
     NewPlayer.Hits := 143; 
     NewPlayer.AtBats := 329; 

     Team.AddObject(NewPlayer.Name, NewPlayer); 

     NewPlayer := TPlayer.Create('Ryan Theriot', 'Short Stop'); 
     NewPlayer.Hits := 87; 
     NewPlayer.AtBats := 203; 

     Team.AddObject(NewPlayer.Name, NewPlayer); 

     Player := FindPlayer('Derrick Lee'); 
     if Player <> nil then 
      Writeln('Player Found: ', Player.Name, ', ', Player.Position) 
     else 
      Writeln('Player not found.'); 
     Writeln; 

     Writeln('Active Roster'); 
     Writeln('-------------'); 

     for I := 0 to Team.Count - 1 do 
      Writeln(TPlayer(Team.Objects[ I ]).Name, #9, 
        TPlayer(Team.Objects[ I ]).Position); 

     Readln; 

     finally 
     //!! Need to free the players. 
     Team.Free; 
     end; 

    end. 
+0

Sonstige Bemerkungen: Self.Name etc. ist nicht im Konstruktor benötigt. Warum eine Konsolen-App verwenden? Warum nicht eine separate Klasse für die Liste der Spieler verwenden? –

+0

Wenn das die ganze Anwendung ist * müssen * Sie keinen Speicher freigeben, da Sie sowieso mit der Anwendung fertig sind – BlackTigerX

+0

@BlackTigerX: Das sieht wie eine einfache Illustration aus. Du hast recht, für diesen Fall, aber der reale Code, den er zu benutzen versucht, ist wahrscheinlich sehr viel komplexer. –

Antwort

13

Mit Delphi 2009 hat der TStringList Konstruktor einen optionalen booleschen Parameter "OwnsObjects". Wenn Sie dies auf "true" setzen, werden die Objekte automatisch freigegeben.

Else können Sie folgendes tun:

for i := Team.Count-1 downto 0 do begin 
    Team.Objects.Free; 
end; 
Team.Free; 

Und übrigens sind die öffentlichen Bereichen abgeraten. Sie verwenden Eigenschaften, damit Sie steuern können, welcher Zugriff auf die Felder möglich ist. Und Sie können Setter-Funktionen hinzufügen, um die Eingabe zu validieren.

type 
    TPlayer = class 
    private 
    FName  : string; 
    FPosition : string; 
    FHits  : Integer; 
    FAtBats : Integer; 
    public 
    constructor Create(const AName, APosition: string); 

    property Name: string read FName; 
    property Position: string read FPosition; 
    property Hits: Integer read FHits write FHits; 
    property AtBats: Integer read FAtBats write FAtBats; 
end; 
+0

DANKE. Ich habe Ihre Lösung in meinen Anwendungen getestet und alle Objekte wurden zerstört. Ich schätze wirklich. – Greener

+0

Ich möchte diese Antwort korrigieren. Vielleicht hat D2009 einen neuen Konstruktor eingeführt oder was - doch die OwnsObjects-Eigenschaft existierte zumindest von Delphi 4 (wahrscheinlich sogar von 16-Bit Delphi 1) und kann nach der Erstellung einfach ein- und ausgeschaltet werden. http: //www.freepascal.org/docs-html/rtl/classes/tstringlist.ownsobjects.html –

3

nur eine Klärung über Gamecat Antwort: Ich weiß nicht, über delphi 2009 aber in der Regel die Eigenschaft Objects benötigen einen Index, und Sie brauchen nicht wirklich einen Reverse-Zyklus, so:

for i := 0 to Team.Count-1 do 
    Team.Objects[i].Free; 
Team.Free; 

oder:

while Team.Count > 0 do 
begin 
    Team.Objects[0].Free; 
    Team.Delete(0); 
end; 
Team.Free; 
+0

Ist die "Team.Delete (0);" Erklärung notwendig? – Argalatyr

+0

Wie er es geschrieben hat, ja. –

+0

@Mason: Du hast recht - ich mache es normalerweise nicht so. – Argalatyr

4

Kinda offensichtlich, aber immer noch - man muss Code nicht schreiben ‚für ... Free‘ jedes Mal, wenn Sie TStringList Objekte löschen möchten. Sie können es in eine globale Funktion einfügen.

procedure FreeObjects(sl: TStringList); 
var 
    i: integer; 
begin 
    for i := 0 to sl.Count - 1 do 
    sl.Objects[i].Free; 
end; 

FreeObjects(Team); 

Oder Sie können es in einen TStringList Helfer einfügen.

TStringListHelper = class helper for TStringList 
public 
    procedure FreeObjects; 
end; 

procedure TStringListHelper.FreeObjects; 
var 
    i: integer; 
begin 
    for i := 0 to Count - 1 do 
    Objects[i].Free; 
end; 

Team.FreeObjects; 
+0

IIRC, Klassenhelfer kann leicht ohne eine Compiler-Warnung gebrochen werden. – mjn

+1

Ja, Klassenhelfer sind problematisch - wenn Sie mehrere Helfer für eine Klasse haben, überschreibt die letzte immer alle anderen. Trotzdem sind sie nützlich. – gabr

+0

@Gabr: Danke für das nützliche Codebeispiel. Ich wusste nicht, dass ein Klassenhelfer so arbeiten kann. – Greener

2

Mit D7, kann ich Unterklasse nur TStingList

+0

Hoffentlich können Sie das in fast jeder objektorientierten Sprache tun ... aber denken Sie an die STL ... vielleicht nicht – jpfollenius