Delphi:如何释放作为方法参数动态创建的对象

6

我有一个带有对象参数的方法(以下是示例代码):

TMyObject=class(TObject)
  constructor Create();
  destructor Destroy();override;
end;

implementation

function doSomething(x:TMyObject):integer;
begin
  //code
end;

procedure test();
var
  w:integer;
begin
  w:=doSomething(TMyObject.Create);
  //here: how to free the created object in line above?
end;

如何在调用方法 doSomething 之外销毁在该方法内创建的对象?

10
不要懒惰,创建一个变量! - smooty86
2
@DalijaPrasnikar https://dev59.com/H-o6XIcBkEYKwwoYSCg1#7640979 - David Heffernan
4
今天我感觉到了强大的力量! - David Heffernan
3
@DalijaPrasnikar,只有当接口参数为const时才会发生泄漏。我说得对吗? - kobik
2
@kobik:你也可以使用 const,但如果你将其作为 doSomething(TMyObject.Create); 传递,它会泄漏。 如果你将其作为 doSomething(TMyObject.Create as IMyInterface); 传递,它不会泄漏。 我总是使用后者的形式。 - Rudy Velthuis
显示剩余14条评论
1个回答

10
为了释放对象实例,你需要拥有一个引用它的变量,并调用Free()方法。
由于你是将对象实例作为参数直接创建,所以你唯一的引用就是在doSomething()参数内部。
你可以在doSomething()内部释放它(但我不建议这样做)。
function doSomething(x: TMyObject): Integer;
begin
  try
    //code
  finally
    x.Free;
  end;
end;

或者,你需要在test()中创建一个额外的变量,将其传递给doSomething(),然后在doSomething()返回后Free它:

procedure test();
var
  w: Integer;
  o: TMyObject
begin
  o := TMyObject.Create;
  try
    w := doSomething(o);
  finally
    o.Free;
  end;
end;

虽然有些人认为使用引用计数对象可以让你直接创建对象,然后通过引用计数来释放它们,但这种构建方式可能行不通,因为会遇到以下编译器问题:

当将新创建的对象实例直接作为const接口参数传递时,编译器应该保留一个隐藏的引用。

这个问题在StackOverflow上得到了前Embarcadero编译器工程师Barry Kelly的确认:

当直接将对象实例作为const接口参数传递时,编译器是否应该发出提示/警告?


1
如果接口参数不是const或者传递时使用as ISomeInterface,它将起作用。请查看我的其他评论。你关于接口被破坏的评论有点恐慌,而且并不真实。 - Rudy Velthuis
@RudyVelthuis 是的,它会像那样工作。但这是极其脆弱的代码,因为如果您更改方法签名,您可能会在完全不相关的位置 - 方法调用中破坏代码。我不建议这样做。而且接口也有问题,因为许多 Delphi 开发人员经常编写使用上述错误的代码。即使是经验丰富的开发人员也是如此。不时地,我必须告诉人们这个错误。 - Dalija Prasnikar
3
修改签名总是一个不好的主意。但使用 as 操作符,无论是否带有 const,都不会导致脆弱性。 - Rudy Velthuis

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接