TJSONObject Destroy方法错误

时间:2013-07-03 08:24:17

标签: 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.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;

我的代码有什么问题?

2 个答案:

答案 0 :(得分:1)

正确的模式 - 甚至内置于Delphi代码模板中

Object-var := Object-Class.Create; // or any other way to create the instance
try
    // ...
finally
  Object-var.Destroy;
end;

相反,您将对象创建放在tryfinally之间的代码中间,这样可以保证:

  • 如果在S.LoadFromFile(fName);中发生某种异常,则会通过垃圾指针调用Destroy

  • 如果在JSONObject:=TJSONObject.ParseJSONValue(S.Text) as TJSONObject;中发生某种异常,则会通过垃圾指针调用Destroy

  • 如果nilJSONObject:=TJSONObject.ParseJSONValue(S.Text) as TJSONObject;的结果,则会Destroy超过nil指针;


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

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

答案 1 :(得分:1)

您有责任免费拨打Get的电话号码。您的责任在于您在Get的代码中调用JSONObject的对象。您必须删除调用innerObject.Destroy

的行

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


如果您调用的引用恰好是Destroy,则通常不会调用nil。而是调用执行Free检查的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;