1

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;

私のコードで何が間違っていますか?

4

2 に答える 2

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;呼び出します。Destroynil


全体的に、DBX JSON についてはあまり良いとは言えませんでした。多くの人がバグや作業の遅さについて不満を漏らしていました。また、オブジェクトの有効期間とは何か、Delphi でそれを管理する方法を理解するのに苦労しているようです。この両方の理由から、DBX の代わりに長年テストされた refcounting-bases JSON ライブラリを使用する方がよいと思います。

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

于 2013-07-03T08:54:46.497 に答える
1

への呼び出しによって返された参照を解放するのは、ユーザーの責任ではありませんGet。その責任はGet、コード内で呼び出すオブジェクトにありますJSONObject。を呼び出す行を削除する必要がありますinnerObject.Destroy

無効なポインター操作エラーが発生する理由は、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;
于 2013-07-03T08:57:06.150 に答える