Delphi 将_记录集结果与TADOConnection.Execute函数一起使用
函数返回一个_记录集 为了简单起见,我目前使用此代码1: 我知道记录集从来都不是空的,所以不用担心BOF 现在我可以用一个局部记录集变量2这样写它 多一点代码 现在我的问题是:由于_记录集是由Execute函数返回的接口变量,如果我没有使用局部rs变量1,它会被正确释放吗?使用我的简化代码1安全吗?这里会有引用计数问题吗 我想了解一些关于这个问题的见解 编辑:我的问题针对具体案例:Delphi 将_记录集结果与TADOConnection.Execute函数一起使用,delphi,delphi-7,Delphi,Delphi 7,函数返回一个_记录集 为了简单起见,我目前使用此代码1: 我知道记录集从来都不是空的,所以不用担心BOF 现在我可以用一个局部记录集变量2这样写它 多一点代码 现在我的问题是:由于_记录集是由Execute函数返回的接口变量,如果我没有使用局部rs变量1,它会被正确释放吗?使用我的简化代码1安全吗?这里会有引用计数问题吗 我想了解一些关于这个问题的见解 编辑:我的问题针对具体案例: V := ADOConnection1.Execute(SQL).Fields[0].Value 当我没有对_记
V := ADOConnection1.Execute(SQL).Fields[0].Value
当我没有对_记录集的局部变量引用时。试试这个:创建一个包含单行的过程
V := AdoConnection1.Execute(Sql).Fields[0].Value;
,在其上放置断点运行应用程序并查看反汇编。你会在排队前看到的
jmp @HandleFinally
有三个电话要打
call @IntfClear
这是编译器为了执行语句而必须访问的三个接口,即
AdoConnection1.Execute返回的记录集接口,
该记录集的字段接口,以及
通过字段[0]获得的特定字段接口。
因此,它在执行源语句后自动生成释放这些接口所需的代码
以下是一个不完美的类比,但它的分解更容易理解;它演示了编译器自动生成的代码,以处理终结接口
给定
Button1Click的CPU反汇编如下所示
红色箭头所示的线是清除接口的位置,不管源代码如何
没有做任何明确的事情来做到这一点。将断点放在
inherited
在TMyClass.Destroy中,你会发现它也会被调用,尽管
源代码没有显式地调用它
正如我所说,上面的类比并不完美。一件有趣的事情是,从使用with construct替代品的角度来看,这很可怕
procedure TForm1.Button1Click(Sender: TObject);
begin
with IMyInterface(TMyClass.Create) do
Caption := IntToStr(GetValue);
end;
如果不使用显式局部变量,编译器将生成与反汇编所示完全相同的代码
当然,q中的情况稍有不同,因为分配给recordset对象的内存位于Ado COM接口的另一侧,因此除了编译器将生成代码以调用接口上的_Release外,无法控制该内存是否被正确取消分配。是,它将被发布。如果您存储该引用并将其存储在执行查询的方法范围之外,则不会发生这种情况。@TLama,您能证明它吗?我这样问是因为我记得读到过关于创建接口但未分配给变量的问题,这些问题与引用计数有关。我错了,@TLama所说的是正确的,但如果您有疑问,只需在某行代码中设置一个断点并打开CPU窗口。然后一步一步地运行代码。你会看到调用方法AddRef和Release的精确时刻。我想你不明白这个问题。我做了一个编辑。事实上,恕我直言,我想我确实理解了你的要求,只是想不出一个直接说明的方法。无论如何,请参见我的编辑,它添加了一个没有显式局部变量的替代方案。在回答另一个关于调用_Release的评论时,并不保证内存被释放,事实上不保证,但在考虑的情况下,内存是由实现接口的Ado对象分配的,除了遵循_AddRef/_Release使用规则外,Delphi无法对其进行控制。关于内存:状态在关闭对象后,在Visual Basic中将对象变量设置为Nothing。我担心的是关上物体后的感觉。我会明确地称之为close,而不是依赖于发布only@Jasper:您为什么不发布一个问题,大意是如果我使用实现它的Delphi对象实例化一个接口,那么在我使用完该对象后是否需要对其调用Free?我肯定你会被答案轰炸,答案说当然不会,因为编译器会处理这个问题。这是人们在Delphi中使用接口的原因之一,即自动生命周期管理。
type
IMyInterface = interface
function GetValue : Integer;
end;
TMyClass = class(TInterfacedObject, IMyInterface)
function GetValue : Integer;
destructor Destroy; override;
end;
TForm1 = class(TForm)
[...]
procedure Button1Click(Sender: TObject);
end;
destructor TMyClass.Destroy;
begin
inherited;
end;
function TMyClass.GetValue: Integer;
begin
Result := 1;
end;
procedure TForm1.Button1Click(Sender: TObject);
var
I : IMyInterface;
begin
I := TMyClass.Create;
Caption := IntToStr(I.GetValue);
end;
inherited
procedure TForm1.Button1Click(Sender: TObject);
begin
with IMyInterface(TMyClass.Create) do
Caption := IntToStr(GetValue);
end;