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 ---