【问题标题】:TJSONObject Destroy method errorTJSONObject 销毁方法错误
【发布时间】:2013-07-03 08:24:17
【问题描述】:

尝试使用 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;

我的代码有什么问题?

【问题讨论】:

  • 为什么不使用SuperObject ?它使用引用计数,因此您可以忘记创建和释放。它还经过多年广泛使用的测试,并且多次报告 DBx JSOn 存在错误或效率低下。 superobject.googlecode.com/git/readme.html
  • BTW try 应该在对象创建之后,而不是之前。不知道您现在是否面临该特定错误,但您的客户在尝试 Destroy 垃圾指针时可能会受到打击。
  • 我最好闭嘴但是:你为什么不使用.Free()?当您强行尝试销毁已被销毁的对象时,通常会抛出“无效指针操作”。 Free() 首先检查对象是否已分配,然后尝试销毁它。但你可能有这样做的理由,我对 Delphi 中的 JSON 真的一无所知......
  • @GünthertheBeautiful .Free 如果对象变量被预置零(IOW 它是另一个对象的属性)或在您使用 FreeAndnil(许多 Delphi 专家认为有害)之后可能会对您有所帮助。在这个特定的代码中,它可能隐藏在问题上(无指针情况),真的。但它不会也不能用垃圾指针的情况提供任何保护。 PS。 .Free 是为对象析构函数引入的,利用了提到的属性自动归零功能。它将在一般代码中使用而不是析构函数只是与计划路径的意外偏差:-)
  • @Arioch'The:我已经使用过超级对象。现在我想使用 DBXJSON ))

标签: json delphi delphi-xe4


【解决方案1】:

正确的模式 - 甚至内置在 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) as TJSONObject; 中发生某些异常,这将通过垃圾指针调用 Destroy。

  • 如果nil 是JSONObject:=TJSONObject.ParseJSONValue(S.Text) as TJSONObject; 的结果,这将在nil 指针上调用Destroy;


总的来说,我听说 DBX JSON 没有什么好处 - 许多人抱怨错误或工作缓慢。而且你看起来也很难理解什么是对象生命周期以及如何在 Delphi 中管理它。出于这两个原因,我认为您最好使用经过多年测试的 refcounting-bases JSON 库而不是 DBX。

http://superobject.googlecode.com/git/readme.html

【讨论】:

  • Arioch - 它不是 Object-var.Free 而不是 Destroy 吗? :)
  • @whosrdaddy Destroy 非常好,因为您确定已分配参考。如果try 执行,则分配对象引用。 Free 仅在析构函数中真正需要。但为了保持一致性,我们倾向于在任何地方使用它。
  • @whosrdaddy 的预期模式是使用.Destroy,但后来在对象析构函数之外使用.Free 的意外趋势被劫持。然而,这只是有趣的历史事实,几乎没有实际价值。
  • 好的,谢谢你们俩。我会记住这个故事中的关键字“一致性”:)
【解决方案2】:

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

您遇到 invalid pointer operation 错误的原因是 JSONObject 正在尝试销毁您已经销毁的对象。


您通常不会调用Destroy,以防您调用它的引用恰好是nil。而是调用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;

您必须在构造函数分配给引用之后立即放置try。如果你把它放在前面,那么你对Free 的调用可以作用于一个未初始化的引用。如果你不马上把它放在后面,那么你可能会泄漏。

对于您的 JSON 对象,您可以这样写:

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

或者你也可以这样做:

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

【讨论】:

  • 哦,我没发现.Destroy。接得好!它是for i := 0 to -1 do 之后的又一个垃圾指针。顺便说一句,关于所有权 - 我在 docwiki.embarcadero.com/Libraries/XE4/en/… 附近找不到你的这个声明 - 它是否在手册中发布?如果我真的想从它的根中分离 JSONValue 并将其作为一个单独的对象保存呢?
  • @Arioch'The 这只是一个简单的双重释放错误。无效的指针是它的标志。 TJSONObject 的文档,呃,很少。但是你会发现所有的例子都支持我的主张。据我所知,Owned 属性默认为 True。
  • 您的评论没有帮助。不要害羞。告诉我它在什么方面没有帮助。你做了什么,行为如何改变?如果您能做的最好的事情就是说“不提供帮助”,那我们就很难提供帮助。
  • 感谢您的链接。阅读“由字节容器拥有”我只能想知道他们所说的 b.c. 是什么意思。这里。阅读docwiki.embarcadero.com/Libraries/XE4/en/… 我只能想知道他们如何期望一个简单的动态数组成为任何东西的所有者! ...而且我认为 SuperObject 的文档记录很糟糕 ;-)
  • @Arioch'The 是的,这完全是火车残骸。另一段只有在您手头有源代码时才能使用的代码。不管怎样,一个快速的网络搜索显示了一些支持我所说的例子。我有 99% 的信心,我就在这里。可能“没有帮助”实际上意味着异常消失了,但泄漏仍然存在。但泄漏可能在其他地方。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-03-10
  • 2010-10-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多