使用SmartPointer作为结果,函数中的数据类型需要显式调用调用

Cha*_*ang 3 delphi smart-pointers

我在http://members.adug.org.au/2011/12/05/smart-pointers/中使用SmartPointer

我定义了一个IStringList:

type
  IStringList = ISmartPtr<TStringList>;
Run Code Online (Sandbox Code Playgroud)

然后我可以使用如下没有内存泄漏提示:

var S: IStringList;
begin
  S := TSmartPtr<TStringList>.Create();
  S.Add('abc');
end;
Run Code Online (Sandbox Code Playgroud)

如果我在函数中使用IStringList作为结果数据类型:

function GetList: IStringList;
begin
  Result := TSmartPtr<TStringList>.Create();
  Result.Add('abc');   // E2010
end;
Run Code Online (Sandbox Code Playgroud)

我收到编译器错误:

[dcc32 Error] Unit2.pas(31): E2010 Incompatible types: 'SmartPointer.ISmartPtr<System.Classes.TStringList>' and 'Procedure of object'
Run Code Online (Sandbox Code Playgroud)

解决方案解决方案是:

  Result.Invoke.Add('abc');
Run Code Online (Sandbox Code Playgroud)

但这打败了使用SmartPointer的语法清洁的目的.有解决方案吗?

Dav*_*nan 5

这是一个非常有趣的.无论出于何种原因,编译器都会Result与其他变量区别对待.我认为没有充分的理由,所以这感觉就像编译错误.

我看到一些解决方法:

  1. 声明一个局部变量,使用它,并通过分配该局部变量来完成该函数Result.
  2. 用parens调用函数:Result().Add('abc').
  3. 使用更好的智能指针.例如,不基于方法调用的智能指针将是一个良好的开端.具有隐式转换运算符的通用记录可能会起作用.
  4. 找到没有bug的编译器版本,如果它确实是编译器错误.
  5. 放弃智能指针并编写传统样式代码.每当我考虑在Delphi中使用智能指针时,我总结说我宁愿看到显式的try/finally块,并了解我的对象何时被创建和销毁.

FWIW,您可以通过剥离智能指针代码并删除泛型类型来大大简化问题.这是我能编写的最干净的SSCCE:

{$APPTYPE CONSOLE}

type
  TFunc = reference to function: TObject;

procedure Foo;
var
  F: TFunc;
begin
  F.ClassName; // compiles
end;

function Bar: TFunc;
begin
  Result().ClassName; // compiles
  Result.ClassName; // [dcc32 Error] E2003 Undeclared identifier: 'ClassName'
end;

begin
end.
Run Code Online (Sandbox Code Playgroud)

我现在确信这是一个编译器错误.

它可能与Delphi相当不寻常的语言特性有关,这意味着对于没有参数的函数,可以省略函数调用括号.这种便利有时会带来歧义.但是,在这种情况下,没有歧义..当应用于a时,运算符没有意义TFunc<TObject>,因此解释这些语句的唯一方法是调用该函数,并将.运算符应用于返回的值.

错误报告:QC123218.