pol*_*zed 2 arrays delphi class dynamic
我需要创建一个包含记录对象数组的类,但是尝试使用SetLength会引发一个Access Violation错误.
请考虑以下带有水果的树对象示例.
type
TFruit = record
color: string;
weight: double;
end;
type
TObjectTree = class
Public
Fruits: array of TFruit;
constructor Create;
procedure AddFruit;
end;
Run Code Online (Sandbox Code Playgroud)
在实现中,当尝试调整Fruit对象数组或初始化为nil时会产生问题.
constructor TObjectTree.Create;
begin
inherited Create;
Fruits:=nil; //Raises an error
end;
procedure TObjectTree.AddFruit(FruitColor: string; FruitWeight: integer);
begin
SetLength(Fruits, Length(Fruits)+1); //Raises an error (when I comment Fruits:=nil; in the constructor)
Fruits[Length(Fruits)].color:=FruitColor;
Fruits[Length(Fruits)].weight:=FruitWeight;
end;
Run Code Online (Sandbox Code Playgroud)
如何在类中使用动态数组?
iam*_*osy 13
更换
Fruits[Length(Fruits)].color:=FruitColor;
Fruits[Length(Fruits)].weight:=FruitWeight;
Run Code Online (Sandbox Code Playgroud)
同
Fruits[High(Fruits)].color:=FruitColor;
Fruits[High(Fruits)].weight:=FruitWeight;
Run Code Online (Sandbox Code Playgroud)
然后它工作.
有些东西告诉我你忽略了创建一个实例TObjectTree.你已经声明了一个TObjectTree变量,但是你没有调用过TObjectTree.Create,或者你直接在你声明的变量上调用它而不是为该变量赋值:
var
Tree: TObjectTree;
begin
// This is wrong.
Tree.Create;
// This is right.
Tree := TObjectTree.Create;
Run Code Online (Sandbox Code Playgroud)
如果没有正确实例化TObjectTree,则没有有效的内存来支持Fruits您尝试使用的字段,因此为其分配值会产生错误.
作为iamjoosy和Rob Kennedy答案的补充,我会这样编码:
procedure TObjectTree.AddFruit(FruitColor: string; FruitWeight: integer);
var
NewCount: Integer;
begin
NewCount := Length(Fruits)+1;
SetLength(Fruits, NewCount);
Fruits[NewCount-1].color := FruitColor;
Fruits[NewCount-1].weight := FruitWeight;
end;
Run Code Online (Sandbox Code Playgroud)
在我看来,更清楚的是Length()只打一次电话.
您不需要Fruits := nil在构造函数中进行分配,因为这会自动发生.实例化对象时,所有字段都为零初始化.也就是说,Fruits := nil不应该引发错误.如果是这样,可能是由于越界数组访问导致内存损坏的结果.
另一个要点是,启用范围检查会产生一个信息错误,可以解释问题.这比依赖访问冲突更有帮助.我不能高度推荐范围检查.
最后,该SetLength(..., Length(...)+1)模式通常会导致内存使用效率非常低,并且可能导致大型列表的性能问题.如果你有Delphi 2009+,我建议TList<TFruit>改用.
| 归档时间: |
|
| 查看次数: |
6240 次 |
| 最近记录: |