Delphi 最后一个未知时刻。释放呼叫
我有两个相同代码的变体:Delphi 最后一个未知时刻。释放呼叫,delphi,Delphi,我有两个相同代码的变体: {$APPTYPE CONSOLE} uses System.SysUtils; type IMyObject1 = interface ['{4411181F-3531-4D30-AB18-A8326F8C2CD0}'] end; IMyObject2 = interface ['{41C88E1A-0360-4AC3-B021-125880B23DE5}'] end; TMyObject = class(TInterf
{$APPTYPE CONSOLE}
uses
System.SysUtils;
type
IMyObject1 = interface
['{4411181F-3531-4D30-AB18-A8326F8C2CD0}']
end;
IMyObject2 = interface
['{41C88E1A-0360-4AC3-B021-125880B23DE5}']
end;
TMyObject = class(TInterfacedObject, IMyObject1, IMyObject2)
public
destructor Destroy; override;
end;
destructor TMyObject.Destroy;
begin
Writeln('Destroy');
inherited;
end;
procedure Variant1;
function GetMyObject: IMyObject2;
var
Obj1: IMyObject1;
begin
Obj1 := TMyObject.Create;
try
Obj1.QueryInterface(IMyObject2, Result);
finally
Obj1 := nil;
end;
end;
var
Obj2: IMyObject2;
begin
Obj2 := GetMyObject;
try
finally
Obj2 := nil;
end;
Writeln('Variant1 end of proc');
end;
function GetMyObject: IMyObject2;
var
Obj1: IMyObject1;
begin
Obj1 := TMyObject.Create;
try
Obj1.QueryInterface(IMyObject2, Result);
finally
Obj1 := nil;
end;
end;
procedure Variant2;
var
Obj2: IMyObject2;
begin
Obj2 := GetMyObject;
try
finally
Obj2 := nil;
end;
Writeln('Variant2 end of proc');
end;
begin
Variant1;
Writeln('---');
Variant2;
Writeln('---');
Readln;
end.
输出
Variant1 end of proc
Destroy
---
Destroy
Variant2 end of proc
---
变量1进程结束
毁灭
---
毁灭
变量2进程结束
---
为什么这两个变体的行为不同?测试环境:Delphi XE7 Windows编译器
在Variant1
中,编译器决定需要创建一个隐式局部变量来保存额外的接口引用。我不明白为什么会这样。但下面是发出的代码,以表明这就是发生的情况:
Variant1
Project1.dpr.46: Obj2 := GetMyObject;
0041A3BD 55 push ebp
0041A3BE 8D45F8 lea eax,[ebp-$08]
0041A3C1 E836FFFFFF call GetMyObject
0041A3C6 59 pop ecx
0041A3C7 8B55F8 mov edx,[ebp-$08]
0041A3CA 8D45FC lea eax,[ebp-$04]
0041A3CD E816F5FEFF call @IntfCopy // copies into the implicit local
由于某些原因,编译器决定在启用优化时不创建隐式局部优化
当然,以上所有内容都是针对32位编译器的。64位编译器又不同了,你不知道吗。在64位编译器中,输出与问题一致,与优化无关
我认为,就我所知,这个问题可能与我的问题有关,没有关于编译器的官方规范或文档,在这里,你能做的最好的事情就是通过观察它的输出经验来学习。优化会改变行为,这意味着您应该尽量避免易受此类行为变化影响的代码。如果您确实可以预测它们。我希望您不介意我重新编写一点问题,使代码成为MCVEI。我确信您知道
GetMyObject
的返回值未定义,会触发未定义的行为。@Johan,返回值在QueryInterface调用中设置。在本例中为nil。@LURD它不是nil
,因为实现对象实现了IMyObject2
@DavidHeffernan,我的错,我在以前的测试中从类定义中注释掉了IMyObject2。感谢您的调查:)
Project1.dpr.70: Obj2 := GetMyObject;
0041A53B 8D45FC lea eax,[ebp-$04]
0041A53E E839FFFFFF call GetMyObject // no such copy here
Destroy
Variant1 end of proc
---
Destroy
Variant2 end of proc
---