以下是Zarko Gajic在Delphi的TStrings项目中释放物体的想法 在About.com.delphi我正在使用Delphi 7,TStringList没有OwnsObjects。
运行以下代码将提示EaccessViolation错误。我不知道为什么和怎么做 走动它来释放物品。
非常感谢。
procedure TForm6.freelist(const alist: TStringList);
var
i: integer;
begin
try
for i:=0 to pred(alist.Count) do begin
if Assigned(alist.Objects[i]) then begin
alist.Objects[i].Free;
alist.objects[i]:=nil;
end;
end;
alist.Clear;
finally
alist.Free;
end;
end;
修改
我添加了这一行, alist.Objects [i]:=指针(0); 并且没有错误。
...
for i:=0 to pred(alist.Count) do begin
if Assigned(alist.Objects[i]) then begin
alist.Objects[i]:=Pointer(0); //newly added line.
alist.Objects[i].Free;
alist.objects[i]:=nil;
end;
end;
...
//But I do not know if this is correct and
// if the efficiency will be compromised.
//This is awkward method?
答案 0 :(得分:5)
以下原始答案回答了您提出的问题。但是,在注释中会发现您没有将对象添加到字符串列表中。您只需添加强制转换为Pointer
的整数。在这种情况下,您不得在这些整数上调用Free
,这将完全解释您的错误。因此,您的问题中的整个代码都是无偿的,您只需在完成后就可以在列表中调用Free
。
将整数转换为指针并将其添加到列表时,除了用于存储指针的内存之外,没有分配内存。这是因为整数是值类型。当您添加真实指针或对象时,您正在添加reference
类型,处理该对象涉及为对象调用Free
或为FreeMem
(或Dispose
)调用指针。
问题的原始答案
您的原始代码是正确的,虽然有点笨重。您遇到的问题是填充Objects[]
的代码。由于我们无法看到代码,我们无法说出你的错误。
现在,说过你的代码很笨重,我就是这样写的:
procedure ClearList(List: TStringList);
var
i: Integer;
begin
for i := 0 to pred(List.Count) do
List.Objects[i].Free;
List.Clear;
end;
关于上述的一些注释:
if Assigned(obj)
之前,您不需要obj.Free
测试。我在这里解释原因:Why should I not use "if Assigned()" before using or freeing things? nil
,将项目设置为Clear
则没有意义。List.Free
。列表的生命周期应与清除列表的代码分开管理。对List.Free
的调用应在与构造列表的调用相同的范围内进行。或者,如果此列表是类的字段,则应该从拥有类的析构函数调用List.Free
。现在,正如我在对此问题和您之前的问题的评论中已经说过的那样,所有这些使用Delphi 7字符串列表的Objects[]
属性的生命周期管理工作都非常不令人满意。泄漏物体太容易了。我会推荐以下替代方案:
TObjectList
而不是TStringList
。创建列表时,将OwnsObjects
属性设置为True
。这将确保当从列表中删除项目时,它将在删除时被销毁。您只需将列表负责其项目的终身管理。请注意,这将要求您将当前字符串列表代码中存储的string
移动为对象的属性。但无论如何,这总是正确的方法,所以我认为这是一个好处而不是缺点。OwnsObjects
的属性。将此问题推送到列表中,让您的更高级代码免受该问题的影响。在列表类的上下文中调试一次代码,然后在知道它工作的情况下一遍又一遍地重复使用它。答案 1 :(得分:-1)
只是一个提示:也许使用TStringList只是使用.indexOf(MyString)
来查找项目。
在这种情况下,将代码移动到TObjectList是一种疯狂,你必须重新发明轮子,更好地说,列表上的外观。
我的建议是,最好避免将对象指针设置为非对象的对象,将cat从Integer放到Pointer中非常容易,但最好还是创建{{1}保持这样的整数(不是在速度和内存方面,只是在不破坏定义方面)。
我必须解释一下:如果你存储一个Integer(不是一个对象)应该是一个Object,你将来很容易得到指针错误操作,当你错误地忘记指针没有指向任何东西时。
哦,还有另一件事你只是通过施法而放松:知道它有一个有效的价值;这是因为Integer(Nil)等于零值,因此您无法知道是否将Nil值或零值强制转换为对象指针。
如果你想要它非常简化,也就是没有属性,得到ans set方法等,这里是一个例子:
TIntegerObject
将整数存储为对象是一个非常基本的类,不需要它有一个析构函数,因为在其中没有任何东西需要被释放。
然后,当您想要将整数存储到TStringList的对象上时,您只需执行以下操作:
TIntegerObject=class(TObject)
public
value:Integer;
constructor Create(value:Integer);
end;
TIntegerObject.Create(value:Integer);
begin
inherited Create;
Self.value:=value;
end;
您可以使用以下命令获取已知字符串值的索引:
MyStringList.Objects[MyIndex]:=TIntegerObject.Create(MyIntegerValue);
然后检查它返回MyIndex:=MyStringList.IndexOf(MyString);
,这意味着这样的字符串不在列表中,它更大意味着字符串在列表的那个位置上。
使用这种方法,您可以检查是否在任何元素上都有一个Integer,只需将其与-1
进行比较,例如:
Nil
获取整数值非常简单:
if Nil=MyStringList.Objects[MyIndex]
then begin
end
else begin
end;
希望这有助于人们更好地编码。
我知道将它编码为MyInteger:=TIntegerObject(MyStringList.Objects[MyIndex]).value;
和MyStringList.Objects[MyIndex]:=TObject(MyInteger);
要容易得多,但这就像做一个FAKE / LIE,这样做就是告诉MyInteger有一个对象的内存起始位置那不存在;当使用它时,容易导致很多错误,内存指针,这样的内存地址可能不属于app,这样可能会导致错误或者最糟糕的事情,代码注入安全漏洞等等,顺便说一下,这是众所周知的已被用于破解游戏机证券,jailbreacks等。
当然,为每个Integer创建一个对象是浪费时间和内存。
由编码人员决定,使用一种或另一种(或其他)方法,但记得要非常精确(现在和未来),我的建议是如果你将整数作为对象(或指针)添加一个评论,永远不要试图释放它们。
另一个警告:将某些对象的某些属性设置为Nil会导致Free,如果有这样的指针'指向不是对象或应用程序分配的内存的内容,将导致错误。
只是最后一个例子,设置一个TObjectList(MyInteger:=Integer(MyStringList.Objects[MyIndex]);
属性设置为OwnsObjects
)将对每个元素以及自己的列表中的Free执行Free(至少在我测试的内容上)这样做任何这些代码都可以释放对象和列表:
请注意,此示例True
的{{1}}属性设置为MyObjectList
。
OwnsObjects
你必须决定使用什么,我只想更安全,我不知道未来多少年我将需要编辑代码。