Delphi - 智能指针和泛型 TList
Delphi - smart pointers and generics TList
我有一个智能指针的实现,我试图在通用 TList 上实现它。
program Project2;
{$APPTYPE CONSOLE}
{$R *.res}
uses
System.SysUtils,
System.Generics.Collections;
type
ISmartPointer<T> = reference to function: T;
TSmartPointer<T: class, constructor> = class(TInterfacedObject, ISmartPointer<T>)
private
FValue: T;
FName: string;
public
constructor Create; overload;
constructor Create(AValue: T); overload;
destructor Destroy; override;
function Invoke: T;
property Name: string read FName write FName;
end;
TTest = class
FString: String;
public
property MyStrign: String read FString write FString;
end;
{ TSmartPointer<T> }
constructor TSmartPointer<T>.Create;
begin
inherited;
FValue := T.Create;
end;
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
if Assigned(FValue) then
FValue.Free;
inherited;
end;
function TSmartPointer<T>.Invoke: T;
begin
Result := FValue;
end;
function TestSMP():ISmartPointer<TList<TTest>>;
var lTTest: ISmartPointer<TTest>;
i: Integer;
begin
Result := TSmartPointer<TList<TTest>>.Create();
for I := 0 to 5 do
begin
lTTest := TSmartPointer<TTest>.Create();
lTTest.FString := IntToStr(i);
Result().Add(lTTest);
end;
end;
var Testlist:ISmartPointer<TList<TTest>>;
i: Integer;
begin
try
Testlist := TestSMP();
for I := 0 to 5 do
Writeln(Testlist[i].FString);
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
Writeln('finished');
Readln;
end.
问题是我无法访问列表中的元素,而且我不知道问题出在哪里。
function TestSMP(): ISmartPointer<TList<TTest>>;
var
lTTest: ISmartPointer<TTest>;
i: Integer;
begin
Result := TSmartPointer<TList<TTest>>.Create();
for I := 0 to 5 do
begin
lTTest := TSmartPointer<TTest>.Create();
lTTest.FString := IntToStr(i);
Result().Add(lTTest);
end;
end;
lTTest
接口变量是唯一使 TTest
实例保持活动状态的东西。每次循环,当您分配给 lTTest
时,先前的 TTest
实例将被销毁。当函数退出时,最终的 TTest
实例,即包含 '5'
的实例被销毁。您精心创建的所有实例现在都已死亡。
您可以通过在 TSmartPointer<T>.Destroy
中放置一个断点并查看调用堆栈来观察这种情况。这样做的后果之一是您的代码实际上是在 TTest
实例被销毁后引用它们。碰巧,你和我都没有观察到运行时错误,尽管这样做显然是错误的。
这里的关键点是,一旦开始使用智能指针管理生命周期,就必须完全这样做。一分钱,一英镑。这几乎促使您更换
ISmartPointer<TList<TTest>>
和
ISmartPointer<TList<ISmartPointer<TTest>>>
那是因为您已经开始通过智能点包装来管理 TTest
实例生命周期。一旦开始这样做,就必须始终如一地这样做。
考虑你程序的这个变体:
{$APPTYPE CONSOLE}
uses
System.SysUtils,
System.Generics.Collections;
type
ISmartPointer<T> = reference to function: T;
TSmartPointer<T: class, constructor> = class(TInterfacedObject,
ISmartPointer<T>)
private
FValue: T;
public
constructor Create;
destructor Destroy; override;
function Invoke: T;
end;
TTest = class
FString: string;
end;
constructor TSmartPointer<T>.Create;
begin
inherited;
FValue := T.Create;
end;
destructor TSmartPointer<T>.Destroy;
begin
FValue.Free;
inherited;
end;
function TSmartPointer<T>.Invoke: T;
begin
Result := FValue;
end;
function TestSMP(): ISmartPointer<TList<ISmartPointer<TTest>>>;
var
lTTest: ISmartPointer<TTest>;
i: Integer;
begin
Result := TSmartPointer<TList<ISmartPointer<TTest>>>.Create();
for i := 0 to 5 do
begin
lTTest := TSmartPointer<TTest>.Create();
lTTest.FString := IntToStr(i);
Result().Add(lTTest);
end;
end;
var
i: Integer;
Testlist: ISmartPointer<TList<ISmartPointer<TTest>>>;
begin
Testlist := TestSMP();
for i := 0 to 5 do
Writeln(Testlist[i]().FString);
Writeln('finished');
Readln;
end.
输出
0
1
2
3
4
5
finished
我觉得我不太喜欢ISmartPointer<TList<ISmartPointer<TTest>>>
这个想法。老实说,我从来没有被智能指针在 Delphi.
中的有效性所说服。
我有一个智能指针的实现,我试图在通用 TList 上实现它。
program Project2;
{$APPTYPE CONSOLE}
{$R *.res}
uses
System.SysUtils,
System.Generics.Collections;
type
ISmartPointer<T> = reference to function: T;
TSmartPointer<T: class, constructor> = class(TInterfacedObject, ISmartPointer<T>)
private
FValue: T;
FName: string;
public
constructor Create; overload;
constructor Create(AValue: T); overload;
destructor Destroy; override;
function Invoke: T;
property Name: string read FName write FName;
end;
TTest = class
FString: String;
public
property MyStrign: String read FString write FString;
end;
{ TSmartPointer<T> }
constructor TSmartPointer<T>.Create;
begin
inherited;
FValue := T.Create;
end;
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
if Assigned(FValue) then
FValue.Free;
inherited;
end;
function TSmartPointer<T>.Invoke: T;
begin
Result := FValue;
end;
function TestSMP():ISmartPointer<TList<TTest>>;
var lTTest: ISmartPointer<TTest>;
i: Integer;
begin
Result := TSmartPointer<TList<TTest>>.Create();
for I := 0 to 5 do
begin
lTTest := TSmartPointer<TTest>.Create();
lTTest.FString := IntToStr(i);
Result().Add(lTTest);
end;
end;
var Testlist:ISmartPointer<TList<TTest>>;
i: Integer;
begin
try
Testlist := TestSMP();
for I := 0 to 5 do
Writeln(Testlist[i].FString);
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
Writeln('finished');
Readln;
end.
问题是我无法访问列表中的元素,而且我不知道问题出在哪里。
function TestSMP(): ISmartPointer<TList<TTest>>;
var
lTTest: ISmartPointer<TTest>;
i: Integer;
begin
Result := TSmartPointer<TList<TTest>>.Create();
for I := 0 to 5 do
begin
lTTest := TSmartPointer<TTest>.Create();
lTTest.FString := IntToStr(i);
Result().Add(lTTest);
end;
end;
lTTest
接口变量是唯一使 TTest
实例保持活动状态的东西。每次循环,当您分配给 lTTest
时,先前的 TTest
实例将被销毁。当函数退出时,最终的 TTest
实例,即包含 '5'
的实例被销毁。您精心创建的所有实例现在都已死亡。
您可以通过在 TSmartPointer<T>.Destroy
中放置一个断点并查看调用堆栈来观察这种情况。这样做的后果之一是您的代码实际上是在 TTest
实例被销毁后引用它们。碰巧,你和我都没有观察到运行时错误,尽管这样做显然是错误的。
这里的关键点是,一旦开始使用智能指针管理生命周期,就必须完全这样做。一分钱,一英镑。这几乎促使您更换
ISmartPointer<TList<TTest>>
和
ISmartPointer<TList<ISmartPointer<TTest>>>
那是因为您已经开始通过智能点包装来管理 TTest
实例生命周期。一旦开始这样做,就必须始终如一地这样做。
考虑你程序的这个变体:
{$APPTYPE CONSOLE}
uses
System.SysUtils,
System.Generics.Collections;
type
ISmartPointer<T> = reference to function: T;
TSmartPointer<T: class, constructor> = class(TInterfacedObject,
ISmartPointer<T>)
private
FValue: T;
public
constructor Create;
destructor Destroy; override;
function Invoke: T;
end;
TTest = class
FString: string;
end;
constructor TSmartPointer<T>.Create;
begin
inherited;
FValue := T.Create;
end;
destructor TSmartPointer<T>.Destroy;
begin
FValue.Free;
inherited;
end;
function TSmartPointer<T>.Invoke: T;
begin
Result := FValue;
end;
function TestSMP(): ISmartPointer<TList<ISmartPointer<TTest>>>;
var
lTTest: ISmartPointer<TTest>;
i: Integer;
begin
Result := TSmartPointer<TList<ISmartPointer<TTest>>>.Create();
for i := 0 to 5 do
begin
lTTest := TSmartPointer<TTest>.Create();
lTTest.FString := IntToStr(i);
Result().Add(lTTest);
end;
end;
var
i: Integer;
Testlist: ISmartPointer<TList<ISmartPointer<TTest>>>;
begin
Testlist := TestSMP();
for i := 0 to 5 do
Writeln(Testlist[i]().FString);
Writeln('finished');
Readln;
end.
输出
0 1 2 3 4 5 finished
我觉得我不太喜欢ISmartPointer<TList<ISmartPointer<TTest>>>
这个想法。老实说,我从来没有被智能指针在 Delphi.