gpt4 book ai didi

Delphi - 智能指针和泛型 TList

转载 作者:行者123 更新时间:2023-12-03 15:52:02 25 4
gpt4 key购买 nike

我有一个智能指针的实现,并且我尝试在通用 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接口(interface)变量是唯一保留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.

输出

012345finished

我认为我不喜欢 ISmartPointer<TList<ISmartPointer<TTest>>> 这个想法非常。老实说,我从来不相信 Delphi 中智能指针的有效性。

关于Delphi - 智能指针和泛型 TList,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28968208/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com