Arrays 带有动态数组的DELPHI类存在SetLength()问题
我需要创建一个类,该类包含记录对象的数组,但尝试使用SetLength会引发访问冲突错误 考虑以下示例中的一个带有水果的树对象Arrays 带有动态数组的DELPHI类存在SetLength()问题,arrays,delphi,class,dynamic,Arrays,Delphi,Class,Dynamic,我需要创建一个类,该类包含记录对象的数组,但尝试使用SetLength会引发访问冲突错误 考虑以下示例中的一个带有水果的树对象 type TFruit = record color: string; weight: double; end; type TObjectTree = class Public Fruits: array of TFruit; constructor Create; procedure AddFruit; end; 在实现中,尝试调整
type
TFruit = record
color: string;
weight: double;
end;
type
TObjectTree = class
Public
Fruits: array of TFruit;
constructor Create;
procedure AddFruit;
end;
在实现中,尝试调整水果对象数组的大小或初始化为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;
如何在类中使用动态数组?替换
Fruits[Length(Fruits)].color:=FruitColor;
Fruits[Length(Fruits)].weight:=FruitWeight;
与
然后它就起作用了。作为对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;
在我看来,只调用一次Length()
更为清晰
您不需要在构造函数中分配Fruits:=nil
,因为这是自动发生的。实例化对象时,所有字段都初始化为零。也就是说,Fruits:=nil
不应引发错误。如果出现这种情况,则可能是由于数组访问超出范围而导致内存损坏
需要指出的另一点是,启用范围检查将导致一个信息错误,该错误可以解释问题。这比依赖访问冲突更有帮助。我不能推荐足够高的范围检查
最后,
SetLength(…,Length(…)+1)
模式通常会导致非常低效的内存使用,并会导致大型列表的性能问题。如果您使用的是Delphi 2009+,我建议您改用TList
。有人告诉我您忽略了创建TObjectTree
的实例。您声明了一个TObjectTree
变量,但您没有调用TObjectTree.Create
,或者您直接对声明的变量调用它,而不是为该变量指定新值:
var
Tree: TObjectTree;
begin
// This is wrong.
Tree.Create;
// This is right.
Tree := TObjectTree.Create;
如果未正确实例化
TObjectTree
,则没有有效内存来支持您尝试使用的Fruits
字段,因此为其赋值会产生错误。+1这更可能解释发生的情况,而不是我的内存损坏解释完全正确。这导致了内存问题。现在可以实例化一个TreeObject并将水果数组设置为nil(以便稍后通过调用要实现的类方法最终清除添加的水果)。在构造函数中将水果设置为nil是毫无意义的。它已经是零了。我通常对这样的代码使用一个函数,返回一个整数,它是新创建项的索引,然后使用result:=length(Fruits);坐骨长度(果实,结果+1);水果[结果]。颜色:=水果颜色代码>它确实比+1/-1对我来说更有意义,而且有时为调用者检索新创建的索引很方便,不会造成速度损失。就我的2美分。@Arnaud同意了,尽管我只会使用TList
,当然它就是这么做的。解释是动态数组是基于0的,运行长度是-1。对,这也是示例中的一个错误。
var
Tree: TObjectTree;
begin
// This is wrong.
Tree.Create;
// This is right.
Tree := TObjectTree.Create;