TJSONObject销毁方法错误
尝试使用TJSONObject(Delphi XE4)解析JSON文件 解析后,我希望销毁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
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
overDestroy
指针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;