假设我有一个功能:
function someFunction: TStringList;
begin
result:=TStringList.Create;
if someConditionIsTrue then
result:=doSomething;
//other code
end;
功能doSomething:
function doSomething: TStringList;
begin
result:=TStringList.Create;
result.Add(something);
end;
如果我运行此代码,一切都按预期工作,但我仍然想知道这是否是传递像stringlist这样的对象的“正确”方法?
字符串列表永远不会被释放,我想知道在调试或其他人试图理解代码时,以这种方式传递对象会变得复杂或混乱。
答案 0 :(得分:6)
"适当"方法是为你建立自己的规则来解决事情的破坏。在函数结果中创建对象很方便,但前提是您遵循自己的严格规则。
在您的情况下,SomeFunction
有内存泄漏。首先,您创建一个TStringList
,然后如果满足某些条件,则在其位置创建另一个TStringList
,完全忽略第一个。{1}}。因此,泄漏记忆。
DoSomething
不应该是返回字符串列表的函数,如果有可能您已经创建了一个字符串列表。相反,只需将其作为一个程序......
procedure DoSomething(AList: TStringList);
begin
AList.Add(Something);
end;
一旦你这样做,SomeFunction
应该是这样的:
function someFunction: TStringList;
begin
Result:= TStringList.Create;
if someConditionIsTrue then
DoSomething(Result);
//other code
end;
"字符表列表永远不会被释放"
我希望这不是设计。您创建的所有内容在某些时候都必须是免费的,特别是如果您有创建其结果的函数。唯一的例外是如果你创建的东西在整个应用程序的持续时间内存在,即使这样,它仍然是极端的共同点,无论如何都要释放它们。
就此而言,我在函数结果中创建对象的唯一时间是我封装了多行代码,否则这些代码行将被多次复制。例如,创建查询。
而不是重复此代码...
Q:= TADOQuery.Create(nil);
Q.Connection:= MyDatabaseConnection;
Q.SetSomeOtherProperties;
......我把它放在一个函数中......
function CreateQuery: TADOQuery;
begin
Result:= TADOQuery.Create(nil);
Result.Connection:= MyDatabaseConnection;
Result.SetSomeOtherProperties;
end;
然后,只要我需要重复该代码,我就可以简单地调用这个函数......
Q:= CreateQuery;
答案 1 :(得分:6)
永远不会释放字符串列表
这本身就是一个问题。就像在评论中提到的那样,会造成内存泄漏。总的来说,我对创建对象并通过结果赋予所有权的函数不屑一顾。当我需要这样做的时候,我通常会命名我的函数"Create*"
,使其尽可能明确地使调用者负责释放内存。
话虽如此,一种更优雅的模式可以实现您的需求:
procedure someFunction;
var vStrings : TStringList;
begin
vStrings := TStringList.Create;
try
if someConditionIsTrue then
doSomething(vStrings);
//other code
finally
vStrings.Free;
end;
end;
procedure doSomething(AStrings : TStringList);
begin
AStrings.Add(something);
end;
如果你真的需要你的" someFunction"返回一个TStringList并且不希望通过参数接收一个,这里如何正确管理它以避免内存泄漏。
function CreateAndInitStrings : TStringList;
begin
Result := TStringList.Create;
try
if someConditionIsTrue then
doSomething(Result);
//other code
except
Result.Free;
raise;
end;
end;