【问题标题】:Freeing multiple Objects in delphidelphi 释放多个对象
【发布时间】:2009-06-19 20:50:55
【问题描述】:

下面,我插入了 Ray Konopka 编写的代码(Coderage 演示文稿的一部分)。我打算使用它,但是,我不确定如何(即时)清理多个对象。 我所有的尝试都没有成功并导致内存泄漏。 任何想法表示赞赏。 谢谢,

  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.

【问题讨论】:

  • 其他说明:构造函数中不需要Self.Name等。为什么要使用控制台应用程序?为什么不对玩家列表使用单独的类?
  • 如果这是整个应用程序,您不需要释放任何内存,因为您已经完成了应用程序
  • @BlackTigerX:这看起来像一个简单的插图。对于这种情况,您是对的,但他尝试使用的实际代码可能要复杂得多。
  • Gamecat, "Self.Name" is 在构造函数中需要。否则,对象的名称字段将不会被设置。
  • 您有演示文稿的链接吗?如果 Konopka 的代码中有“finally”部分中的注释,那么我想知道遗漏是否是演示的重点。

标签: delphi


【解决方案1】:

在 Delphi 2009 中,TStringList 构造函数有一个可选的布尔参数“OwnsObjects”。如果将其设置为 true,则会自动释放对象。

您还可以执行以下操作:

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

顺便说一句,不鼓励使用公共字段。您最好使用属性,这样您就可以控制对字段的访问权限。并且您可以添加 setter 函数来验证输入。

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;

【讨论】:

  • 谢谢。我已经在我的应用程序中测试了您的解决方案,并且所有对象都被销毁了。我真的很感激。
  • 我想更正这个答案。也许 D2009 引入了新的构造函数或什么 - 但是 OwnsObjects 属性至少存在于 Delphi 4(甚至可能来自 16 位 Delphi 1)并且可以在创建后轻松打开/关闭。 freepascal.org/docs-html/rtl/classes/…
【解决方案2】:

有点明显,但仍然 - 您不必每次要清除 TStringList 对象时都编写“for ... Free”代码。你可以把它放到一个全局函数中。

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

FreeObjects(Team);

或者你可以把它放到一个 TStringList 助手中。

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;

【讨论】:

  • IIRC,类助手可以很容易地被破坏,甚至没有编译器警告。
  • 是的,类助手是有问题的——如果一个类有多个助手,最后一个总是会覆盖所有其他的。不过,它们还是有用的。
  • @Gabr:感谢您提供有用的代码示例。我不知道类助手可以这样使用。
  • 如果我有其他选择,我不会使用 classhelpers。在自己的代码中(不与 VCL 进行大量交互),更容易简单地创建派生并覆盖销毁,就像 Gedean 下面所说的那样。
【解决方案3】:

只是对gamecat回答的澄清:我不知道delphi 2009,但通常 Objects 属性需要一个索引,而你并不真的需要一个反向循环,所以:

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

或:

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

【讨论】:

  • 是“Team.Delete(0);”需要声明吗?
  • 他的写作方式,是的。
  • 这不是最佳的,特别是对于大型收藏。恕我直言,第一个代码窥探更好。
【解决方案4】:

使用 D7,我可以将 TStingList 子类化

【讨论】:

  • 希望你可以用几乎任何面向对象的语言来做到这一点......但考虑到 STL......也许不是
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-06-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-06-26
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多