我是具有C背景的Delphi的新手,并试图弄清楚如何实现智能指针 . 我遇到了以下帖子,我试图将其作为我自己的起点:Delphi - smart pointers and generics TList
但是我无法使用Delphi XE7编译以前的代码(编译器错误在代码中显示为注释) . 如果有人真正解释了代码的逻辑,我也会非常感激(最初我想将该类用作实用程序类中的一个drop,但现在我想了解实际发生的情况) . 我隐约明白,因为智能指针实现继承自TInterfacedObject,所以它是引用计数但超出此范围的任何东西对我来说都没有意义:)
unit SmartPointer;
interface
uses
SysUtils, System.Generics.Collections;
type
ISmartPointer<T> = reference to function: T;
// complains ISmartPointer<T> expecting an interface type
TSmartPointer<T: class, constructor> = class(TInterfacedObject,ISmartPointer<T>)
private
FValue: T;
public
constructor Create; overload;
constructor Create(AValue: T); overload;
destructor Destroy; override;
function Invoke: T;
end;
implementation
{ TSmartPointer<T> }
constructor TSmartPointer<T>.Create;
begin
inherited;
FValue := T.Create;
end;
// complains: overload procedure TSmartPointer.Create must be marked with the overload directive
constructor TSmartPointer<T>.Create(AValue: T);
begin
inherited Create;
if AValue = nil then
FValue := T.Create
else
FValue := AValue;
end;
destructor TSmartPointer<T>.Destroy;
begin
FValue.Free;
inherited;
end;
function TSmartPointer<T>.Invoke: T;
begin
Result := FValue;
end;
end.
试图使用以前的智能指针与以下测试代码导致编译器错误...我错过了什么?
program TestSmartPointer;
{$APPTYPE CONSOLE}
{$R *.res}
uses
System.SysUtils, SmartPointer;
type
TPerson = class
private
_name : string;
_age : integer;
public
property Name: string read _name write _name;
property Age: integer read _age write _age;
end;
var
pperson : TSmartPointer<TPerson>;
begin
try
{ TODO -oUser -cConsole Main : Insert code here }
pperson := TSmartPointer<TPerson>.Create();
// error on next line: undeclared Identifier: Name
pperson.Name := 'John Doe';
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
end.
1 回答
您必须将引用变量声明为
ISmartPointer<TPerson>
:下面的代码也会编译,但在这种情况下它不会自动释放内存,因为当您将引用计数的对象实例存储到对象引用中时,您会搞乱其引用计数机制 . 根据代码,它可能导致内存泄漏或底层对象实例的过早破坏 .
最后,以下代码说明了正确的智能指针用法:
Some interface basics
接口定义了一个 Contract - 实现接口的类必须具有的功能,而不提供特定的实现 .
IFoo
接口声明意味着当您引用IFoo
时,可以在该引用上调用Foo
方法,但这就是您所能做到的 .当类实现接口时,它必须实现该接口的所有方法 .
IFoo
中的方法Foo
将从TFoo
或TOtherFoo
映射到方法Foo
. 特定接口的实现可以在不同的类中不同 .How a smart pointer actually works
ISmartPointer<T>
被声明为匿名函数 .上面的声明等同于
Invoke
函数的接口两者之间的区别(我们感兴趣的是),使用匿名函数/方法,您不必显式调用
Invoke
;编译器会为你做这件事 .由于
ISmartPointer<T>
是一个匿名函数,它实际上是TSmartPointer<T>
类声明中的接口,Invoke
方法将映射到ISmartPointer<T>
.因此,当您在窗帘后写
pperson.Name
转换为pperson.Invoke
函数调用,该函数从FValue
返回TPerson
实例,TPerson
具有编译器可识别的Name
属性 .由于
TSmartPointer<T>
是引用计数类,因此当您使用ISmartPointer<T>
引用时,基础TSmartPointer<T>
对象实例以及FValue
中包含的T
实例将在ISmartPointer<T>
引用超出范围时自动释放,或者将其设置为nil
in码 .