以下代码尝试使用Delphi的引用计数功能.
但是,FullDebugMode报告中的FastMM4 DoStuff1会导致内存泄漏,而DoStuff2不会.你能帮忙评论一下为什么吗?这两个程序不应该在幕后表现完全相同吗?
program Project_SO;
{$APPTYPE CONSOLE}
uses
FastMM4,
SysUtils;
type
ITestFunc = interface
['{B3F6D9A7-FC77-40CE-9BBF-C42D7037A596}']
function DoIt(X,Y: Integer): Integer;
end;
TTestFunc = class(TInterfacedObject, ITestFunc)
public
function DoIt(X,Y: Integer): Integer;
end;
TTestFuncClass = class of TTestFunc;
{ TTestFunc }
function TTestFunc.DoIt(X, Y: Integer): Integer;
begin
Result := X + Y;
end;
function DoStuff1(Num1, Num2: Integer; OperationClass: TTestFuncClass): Integer;
begin
Result := ITestFunc(OperationClass.Create).DoIt(Num1, Num2);
end;
function DoStuff2(Num1, Num2: Integer; OperationClass: TTestFuncClass): Integer;
var I: ITestFunc;
begin
I := ITestFunc(OperationClass.Create);
Result := I.DoIt(Num1, Num2);
end;
begin
Writeln(IntToStr(DoStuff1(3, 6, TTestFunc)));
Writeln(IntToStr(DoStuff2(3, 6, TTestFunc)));
end.
Run Code Online (Sandbox Code Playgroud)
Result := ITestFunc(OperationClass.Create).DoIt(Num1, Num2);
Run Code Online (Sandbox Code Playgroud)
这里没有提到所采用的接口.将接口分配给变量或作为by值参数传递时,将引用该引用.实际上,作为by值参数传递,可以被认为在语义上等同于分配给被调用者帧中的局部变量.
但是在这段代码中没有任何地方可以参考.因此,由于没有任何参考接口,因此没有机制可以将其销毁.因此泄漏.
var
I: ITestFunc;
begin
I := ITestFunc(OperationClass.Create);
Result := I.DoIt(Num1, Num2);
end;
Run Code Online (Sandbox Code Playgroud)
在此变体中,在进行分配时进行参考.当局部变量I离开范围时,其引用计数减少到零并且实现对象被销毁.
请注意,未经检查的演员表在这里是不必要的.编译器非常清楚TTestFunc实现ITestFunc和代码应该更好地编写如下:
var
I: ITestFunc;
begin
I := OperationClass.Create;
Result := I.DoIt(Num1, Num2);
end;
Run Code Online (Sandbox Code Playgroud)
正如评论中所建议的那样,您可以删除局部变量并使用经过检查的as强制转换:
Result := (OperationClass.Create as ITestFunc).DoIt(Num1, Num2);
Run Code Online (Sandbox Code Playgroud)
执行as强制转换的结果是声明了一个隐式局部变量,接口被分配给该变量.这意味着引用计数递增到1,然后当隐式本地离开作用域时递减到零.
最后,您的TTestFunc类应该有一个虚拟构造函数,因为您打算使用元类对其进行实例化.
| 归档时间: |
|
| 查看次数: |
200 次 |
| 最近记录: |