TJSONObject销毁方法错误

TJSONObject销毁方法错误,json,delphi,delphi-xe4,Json,Delphi,Delphi Xe4,尝试使用TJSONObject(Delphi XE4)解析JSON文件 解析后,我希望销毁TJSONObject以防止内存泄漏,但是: procedure TfmMain.ReadIngrJSON(const fName: string); var i: integer; S: TStringList; JSONObject, innerObject: TJSONObject; innerArray: TJSONArray; begin S:=TStringList.Cr

尝试使用TJSONObject(Delphi XE4)解析JSON文件

解析后,我希望销毁TJSONObject以防止内存泄漏,但是:

procedure TfmMain.ReadIngrJSON(const fName: string);
var i: integer;
    S: TStringList;
    JSONObject, innerObject: TJSONObject;
    innerArray: TJSONArray;
begin
S:=TStringList.Create;
try
  S.LoadFromFile(fName);
  JSONObject:=TJSONObject.ParseJSONValue(S.Text) as TJSONObject;
  if Assigned(JSONObject) then
    begin
      SetLength(ingrArray, JSONObject.Size);
      for i := 0 to JSONObject.Size-1 do
        begin
          ingrArray[i].id:=JSONObject.Get(i).JsonString.Value;
          innerObject:=JSONObject.Get(ingrArray[i].id).JsonValue as TJSONObject;

          innerArray:=innerObject.Get('en').JsonValue as TJSONArray;
          ingrArray[i].name[0]:=innerArray.Get(0).Value;
          ingrArray[i].units[0]:=innerArray.Get(1).Value;

          innerArray:=innerObject.Get('ru').JsonValue as TJSONArray;
          ingrArray[i].name[1]:=innerArray.Get(0).Value;
          ingrArray[i].units[1]:=innerArray.Get(1).Value;
          innerArray:=nil;
        end;
      innerObject.Destroy;

      for i := 0 to Length(ingrArray)-1 do
        listIngredients.Items.Add(ingrArray[i].name[1]);

    end
  else
    raise Exception.Create('no JSON data');
finally
  JSONObject.Destroy;  //here is an error 'invalid pointer operation'
  S.Free;
end;

end;

我的代码出了什么问题?

正确的模式-即使是内置在Delphi代码模板中也是如此

Object-var := Object-Class.Create; // or any other way to create the instance
try
    // ...
finally
  Object-var.Destroy;
end;
相反,您将对象创建放在
try
finally
之间的代码中间,这样可以保证:

  • 如果
    S.LoadFromFile(fName)中发生异常
    这将通过垃圾指针调用
    Destroy

  • 如果
    JSONObject:=TJSONObject.ParseJSONValue(S.Text)作为TJSONObject发生异常
    这将通过垃圾指针调用
    Destroy

  • 如果
    nil
    JSONObject的结果:=TJSONObject.ParseJSONValue(S.Text)作为TJSONObject
    这将调用
    Destroy
    over
    nil
    指针


总的来说,我对dbxjson没有什么好感——许多人抱怨有bug或工作缓慢。而且,您在理解什么是对象生命周期以及如何在Delphi中管理对象生命周期方面似乎也有困难。出于这两个原因,我认为最好使用JSON库而不是DBX


释放调用
Get
返回的引用不是您的责任。这一责任在于调用
Get
的对象,即
JSONObject
中的对象。必须删除调用
innerObject.Destroy
的行

遇到无效指针操作错误的原因是
JSONObject
正在尝试销毁您已经销毁的对象


如果调用它的引用恰好是
nil
,则通常不调用
Destroy
。相反,调用
Free
,执行
nil
检查,如果引用为nil,则跳过调用
Destroy

最后,您使用Finally是不正确的。正确的模式是:

obj := TSomeClass.Create;
try
  // use obj
finally
  obj.Free; // obj.Destroy is also fine in this case because obj <> nil
end;
或者你也可以这样做:

JSONObject := TJSONObject.ParseJSONValue(S.Text) as TJSONObject;
try
  if Assigned(JSONObject) then
  begin
    ....
  end;
finally
  JSONObject.Free;
end;

为什么不使用
SuperObject
?它使用refcounting,因此您可以忘记创建和释放。它还经过多年的广泛使用测试,DBx JSOn被多次报告存在错误或效率低下。顺便说一句,try应该在对象创建之后,而不是之前。我不知道你现在是否面临这个特定的错误,但是当你的客户试图
销毁垃圾指针时,他们可能会被这个错误击中。我最好闭嘴,但是:你为什么不使用
.Free()
?当您强制尝试销毁已销毁的对象时,通常会引发“无效指针操作”
Free()
首先检查对象是否已分配,然后尝试销毁它。但你可能有理由这么做,我对德尔福的JSON一无所知……G UnthEththEngult<代码>。如果VAR被预归零(IOW是另一个对象的属性),或者在你使用< FreeAndnil > <代码>(许多德尔福大师认为有害)之后,免费< /Cord>可以帮助你。在这个特定的代码中,它可能隐藏在问题上(零指针情况),真的。但它不会也不能对垃圾指针案例提供任何保护。PS.
.Free
是为对象析构函数引入的,它利用了前面提到的属性自动归零功能。在通用代码中使用它而不是析构函数只是对计划路径的意外偏离:-)@Arioch'The:我已经使用了superobject。现在我想使用DBXJSON)Arioch-它不是Object-var.Free而不是Destroy吗@销毁
的人很好,因为您肯定知道已经分配了引用。如果执行了
try
,则会指定对象引用<代码>免费仅在析构函数中真正需要。但为了一致性,我们倾向于在任何地方都使用它。@whosrdaddy预期的模式使用的是
.Destroy
,但后来在对象析构函数之外使用
.Free
的意外趋势使它受到了极大的阻碍。然而,这只是一个有趣的历史事实,几乎没有实际价值。好吧,谢谢你们两位。我会记得这个故事中的关键词“一致性:)哦,我没有发现
。Destroy
。抢手货对于i:=0到-1 do,它是
之后的另一个垃圾指针。顺便说一句,关于所有权-我在arounf找不到你的这一主张-它在手册中发表了吗?如果我真的想从它的根中分离JSONValue并将其作为一个单独的对象,该怎么办?@Arioch'The这只是一个简单的无双重错误。无效指针是这方面的标志。
TJSONObject
的文档非常稀疏。但你会发现所有的例子都支持我的主张。据我所知,该属性默认为
True
。您的评论没有帮助。别害羞。告诉我它在什么方面没有帮助。你做了什么,行为如何改变?如果你能做的就是说“不要帮助”,这并不能让我们很容易地提供帮助。谢谢链接。读到“由字节容器拥有”,我只想知道这里的b.c.是什么意思。读到这里,我只想知道他们怎么会期望一个简单的动态数组成为任何东西的所有者。。。我认为SuperObject的文档记录得很糟糕;-)@是的,这完全是一场火车失事。另一段代码,只有在手头有源代码的情况下才能使用。总之,一个快速的网络搜索展示了一些支持我所说的例子。我99%相信我就在这里。可能“没有帮助”实际上意味着异常消失了,但泄漏仍然存在。但泄漏可能在其他地方。
JSONObject := TJSONObject.ParseJSONValue(S.Text) as TJSONObject;
try
  if Assigned(JSONObject) then
  begin
    ....
  end;
finally
  JSONObject.Free;
end;