【问题标题】:Object creation not assigned to variable对象创建未分配给变量
【发布时间】:2020-10-07 14:12:47
【问题描述】:

我想使用类的方法而不将其创建分配给变量。例如:

type
  TMyObject = class
  public
    procedure DoSomething;
  end;

implementation

procedure MyObjDoesSomething;
begin
  TMyObject.Create.DoSomething;
end;

{ TMyObject }

procedure TMyObject.DoSomething;
begin
  // ...
end;

如您所见,在MyObjDoesSomething 中,我没有将TMyObject.Create 分配给TMyObject 变量。

这是否会对内存使用产生某种影响,甚至是我没有想到的其他影响?

【问题讨论】:

  • 我很想知道你为什么不想使用局部变量?
  • @DavidHeffernan 我在 Remy Lebeau 的回答下回答了
  • 似乎很清楚的是,这个问题比问题中的代码更多。好像你有问题,但是这里的代码并没有表达出来。您应该按照 Remy 所说的去做,并提供一个 minimal reproducible example 来演示实际问题。

标签: memory-management delphi-10.3-rio


【解决方案1】:

是的,影响很大:内存泄漏!

你调用了一个对象的构造函数,但从不释放创建的对象。每次调用 MyObjDoesSomething 时,都会泄漏一个对象实例。

要解决这个问题,你可以像这样创建一个 DoSomething 的类方法:

type
  TMyObject = class
  public
    class procedure DoSomething;
  end;

然后你可以调用 DoSomething 而不创建这样的对象:

procedure MyObjDoesSomething;
begin
  TMyObject.DoSomething;
end;

作为类方法,DoSomething 实现不能使用对象实例变量(字段)。

【讨论】:

    【解决方案2】:

    如果你 Create 一个对象为它分配内存,你必须在使用完对象后调用 Free() 来释放该内存,否则内存泄漏,如果你使用它会随着时间的推移影响内存多次创建这些对象。

    如果您不想使用显式变量来引用对象(为什么?),您可以使用 with 块,例如:

    procedure MyObjDoesSomething;
    begin
      with TMyObject.Create do
      try
        DoSomething;
      finally
        Free;
      end;
    end;
    

    另一种选择是让类实现interface,然后您可以让编译器的接口引用计数为您处理释放对象。这比上面的开销要多一点,但是您不必担心手动处理内存,例如:

    type
      IMyObject = interface
        ['{896FF4FA-A974-4A8B-9EA5-414C138635E4}']
        procedure DoSomething;
      end;
    
      TMyObject = class(TInterfacedObject, IMyObject)
      public
        procedure DoSomething;
      end;
    
    implementation
    
    procedure MyObjDoesSomething;
    begin
      (TMyObject.Create as IMyObject).DoSomething;
    end;
    
    { TMyObject }
    
    procedure TMyObject.DoSomething;
    begin
      // ...
    end;
    

    但实际上,只需使用变量即可。使用它无需任何费用:

    procedure MyObjDoesSomething;
    var
      Obj;
    begin
      Obj := TMyObject.Create;
      try
        Obj.DoSomething;
      finally
        Obj.Free;
      end;
    end;
    

    【讨论】:

    • With 构造经常被劝阻。其实这是一个有争议的话题。
    • @fpiette 是的,但在这种简单的情况下,它可能引起的争议性问题相当没有实际意义。
    • 虽然它并不是 with 的真正用法。在一个说教的例子中这些问题没有实际意义是没有抓住重点的。重要的是现实世界的棕地维护问题。
    • 在我的真实环境中,TMyObject.DoSomething 使用 RTTI 将他的一个方法分配给另一个对象的事件属性。如果我在DoSomething 之后调用Free,当另一个对象的事件触发时我会遇到访问冲突,所以我想知道是否像在我的示例中那样调用DoSomething 可能是一种解决方法......实现接口没有解决了这个问题,所以我决定存储TMyObject(而不是有一个局部变量)并在另一个对象被销毁时释放它。
    • @MarinaFinetti "如果我在 DoSomething 之后调用 Free,则当另一个对象的事件触发时,我会遇到访问冲突" - 如果您是 Free,这是有道理的拥有用于事件处理程序的方法的对象,并且该方法尝试通过其Self 指针访问该对象的成员。 “实现接口并没有解决问题” - 如果你使用接口对象作为事件处理程序,你必须采取额外的措施来确保对象的引用计数不会在对象运行时降为 0分配给事件。基本上,同样的问题 - 对象的过早销毁
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-10-04
    • 2016-11-19
    • 2016-08-04
    • 2012-07-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多