我的班级结构如下。
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}编译指令,但是无论如何添加该指令都不太可行。
答案 0 :(得分:1)
正确的代码是这样:
ObjectA := TObjectA.Create;
ObjectB := TObjectB.Create(ObjectA);
try
...
finally
ObjectB.Free;
end;
ObjectB
拥有ObjectA
的所有权,因此销毁它是它的工作。调用代码已经承担了该责任,因此无需执行其他任何操作。