我试图实现类似于Delphi的TList类的顺序链表类。这里的类不是允许用户设置count属性,而是自动递增/递减count属性。因此,类不是在setcount过程内初始化数组,而是在将对象引用添加到数组之前初始化数组元素。这是代码:
PObjectarray = ^TObjectarray;
TObjectarray = array of TObject;
TSequentialList = class
private
FObjects: PObjectarray;
FCapacity: Integer;
FCount: Integer;
protected
procedure GrowList;virtual;
procedure SetCapacity(aValue: Integer);
public
constructor Create(aCapacity: Integer); overload;
Constructor Create;overload;
procedure Add(aObject:TObject);
procedure Delete(aIndex:Integer);
destructor Destroy;override;
End;
实施: -
procedure TSequentialList.Add(aObject: TObject);
begin
if FCount=FCapacity then
GrowList;
FillChar(FObjects^[FCount],sizeof(TObject),0);//Initialize the FCount's member space
FObjects^[FCount]:=aObject;
Inc(FCount);
end;
constructor TSequentialList.Create(aCapacity: Integer);
begin
FCapacity := 0;
FCount := 0;
SetCapacity(aCapacity);
end;
constructor TSequentialList.Create;
begin
FCapacity := 0;
FCount := 0;
end;
procedure TSequentialList.Delete(aIndex: Integer);
var tmpObj:TObject;
i:Integer;
begin
if (aIndex>=FCount) or (aIndex<0) then raise ELinkedListException.Create('Invalid Index in Delete..!');
tmpObj:=FObjects^[aIndex];
tmpObj.Free;
System.Move(FObjects^[aIndex+1],FObjects^[aIndex],(FCount-aIndex)* SizeOf(TObject));
Dec(FCount);
end;
destructor TSequentialList.Destroy;
begin
SetCapacity(0);
inherited;
end;
procedure TSequentialList.GrowList;
var delta:Integer;
begin
if FCapacity>64 then
delta:=FCapacity div 64
else if FCapacity>16 then
delta:=8
else delta:=4;
SetCapacity(FCapacity+delta);
end;
procedure TSequentialList.SetCapacity(aValue: Integer);
var i:Integer;
begin
if FCapacity <> aValue then begin
if aValue<FCount then begin
for i := FCount-1 downto aValue do
Delete(i);
end;
ReallocMem(FObjects, aValue*sizeof(TObject));
FCapacity := aValue;
end;
end;
用法://不起作用
procedure TForm2.Button1Click(Sender: TObject);
var lst:TSequentialList;
obj:TIntObj;
begin
lst:=TSequentialList.Create(4);
obj:=TIntObj.Create(10);
lst.Add(obj);
lst.Add(TIntObj.Create(20));
lst.Free;
end;
退出上述方法后系统挂起。请指导我该程序有什么问题。
答案 0 :(得分:1)
我首先要说的不是链接列表。这是一个非常不同的结构。更重要的是,您应该只使用Delphi提供的内置类,而不是重新实现TObjectList
。
您的代码的基本问题是您错误地使用动态数组。您不能使用ReallocMem
之类的原始分配函数。像GetMem
,ReallocMem
等函数用于原始指针。动态数组的生命周期由编译器/运行时库管理。
要分配动态数组,您必须使用SetLength
。
另一个重要错误是对System.Move
的调用会移动错误数量的元素。
以下代码是代码的简化和更正变体。
type
TMyObjectList = class
private
FObjects: array of TObject;
FCount: Integer;
protected
procedure GrowList;
procedure SetCapacity(aValue: Integer);
public
constructor Create(aCapacity: Integer); overload;
constructor Create; overload;
destructor Destroy; override;
procedure Add(aObject: TObject);
procedure Delete(aIndex: Integer);
end;
constructor TMyObjectList.Create(aCapacity: Integer);
begin
inherited Create;
SetCapacity(aCapacity);
end;
constructor TMyObjectList.Create;
begin
Create(0);
end;
destructor TMyObjectList.Destroy;
begin
SetCapacity(0);
inherited;
end;
procedure TMyObjectList.Add(aObject: TObject);
begin
if FCount = Length(FObjects) then
GrowList;
FObjects[FCount] := aObject;
Inc(FCount);
end;
procedure TMyObjectList.Delete(aIndex: Integer);
begin
if (aIndex >= FCount) or (aIndex < 0) then
raise Exception.Create('Invalid Index in Delete..!');
FObjects[aIndex].Free;
System.Move(FObjects[aIndex+1], FObjects[aIndex],
(FCount-aIndex-1)*SizeOf(TObject));
Dec(FCount);
end;
procedure TMyObjectList.GrowList;
var
delta: Integer;
begin
if Length(FObjects) > 64 then
delta := Length(FObjects) div 64
else if Length(FObjects) > 16 then
delta := 8
else
delta := 4;
SetCapacity(Length(FObjects) + delta);
end;
procedure TMyObjectList.SetCapacity(aValue: Integer);
var
i: Integer;
begin
if Length(FObjects) <> aValue then
begin
for i := aValue to FCount-1 do
FObjects[i].Free;
SetLength(FObjects, aValue);
end;
end;
但我建议您使用已知可用的内置RTL类。例如,如果您使用的是现代版本的Delphi,则可以使用System.Generics.Collections
中的一个通用容器。在您的情况下,TObjectList<T>
似乎就是您所需要的。在较旧的Delphi版本中,您可以使用TObjectList
单元中的Contnrs
。
答案 1 :(得分:0)
delete-method中的这一行肯定是错误的:
for i := FCount-1 downto aValue do
Delete(i);
改为呼叫Delete(aValue)
。
但是,您的代码并未实现链接列表。它看起来非常像您正在尝试实现TObjectList。