检查空闲对象实例

时间:2019-04-13 16:50:48

标签: delphi dependency-injection memory-leaks

我的班级结构如下。

TObjectA = class
    ...
end;

TObjectB = class
    private
        FDependencyObjectA
    public
        constructor Create(const DependencyA: TObjectA);
        destructor Destroy; override;
end;

{ TObjectB }

constructor TObjectB.Create(const DependencyA: TObjectA);
begin
    FDependencyObjectA := DependencyA;
end;

destructor TObjectB.Destroy;
begin
  FDependencyObjectA.Free;
  FDependencyObjectA := nil; 
  inherited;
end;

我正在尝试找到一种可用于这两个用例的解决方案。

// Use cases

// First case 
// Works with Free on Destroyer
// Does not work without Free on Destroyer
procedure TForm1.Button1Click(Sender: TObject);
var
 ObjectB: TObjectB;
begin
   ObjectB := TObjectB.Create(TObjectA.Create);
   try
       ...
   finally
       ObjectB.Free; 
   end;
end;


// Second case
// Does not work with Free on Destroyer
// Works without Free on Destroyer
procedure TForm1.Button1Click(Sender: TObject);
var
 ObjectA: TObjectA;
 ObjectB: TObjectB;
begin
   ObjectA := TObjectA.Create;
   ObjectB := TObjectB.Create(ObjectA);
   try
       ...
   finally
       // Depending on the implementation of the Destroyer or the this finally
       // Can raise Access Violation, Invalid Pointer or Memory Leak
       ObjectB.Free; 
       ObjectA.Free;
   end;
end;

一种解决方案是验证ObjectA已经没有内存了。但是我不知道只有在对象空闲时才进行检查,我知道对对象何时为空进行检查。

// Third case (Trying for a solution)
procedure TForm1.Button1Click(Sender: TObject);
var
 ObjectA: TObjectA;
 ObjectB: TObjectB;
begin
   ObjectA := TObjectA.Create;
   ObjectB := TObjectB.Create(ObjectA);
   try
       ...
   finally
       ObjectB.Free;       
       // It would work fine if Assigned returned false, but always returns true
       if Assigned(ObjectA) then  // or ObjectA <> nil
         ObjectA.Free;
         // If I use just assign nil instead of Free, compile throws a hint
         // ObjectA := nil;
         // H2077 Value assigned to 'Your_Variable' never used
   end;
end;

另一种解决方案是使用保留字var注入依赖项。但我想先评估其他可能性。

在Delphi中,有什么方法可以检查对象是否只是自由对象,而不仅仅是nil?

或者在前两个用例中是否存在任何解决方法,而没有访问冲突,无效指针,内存泄漏或编译提示错误?

我不只是想采用一个用例,也不是要不断检查对象的销毁者以了解如何实现新的功能/过程。这对于日常实施或新开发人员进入项目时都是不利的。我们将不得不解释所有这些小规则,并且还要不断地审查实现是否正确。

编辑:

我知道Delphi具有用于接口的ARC,但是并非所有对象都将实现接口。

要获取提示,可以使用{$ Hints Off}编译指令,但是无论如何添加该指令都不太可行。

1 个答案:

答案 0 :(得分:1)

正确的代码是这样:

ObjectA := TObjectA.Create;
ObjectB := TObjectB.Create(ObjectA);
try
  ...
finally
  ObjectB.Free;       
end;

ObjectB拥有ObjectA的所有权,因此销毁它是它的工作。调用代码已经承担了该责任,因此无需执行其他任何操作。