如何在函数之间传递对象?
How do you pass objects between functions?
假设我有一个函数:
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;
如果我 运行 此代码一切正常,但我仍然想知道这是否是 "proper" 传递对象(如字符串列表)的方法?
字符串列表永远不会被释放,我想知道在调试或其他试图理解代码的人时,以这种方式传递对象是否会变得复杂或混乱。
"proper" 方法是让您建立自己的销毁规则。在函数结果中创建对象很好,但前提是您要遵循自己的严格规则。
在您的情况下,SomeFunction
存在内存泄漏。首先,您创建一个 TStringList
,然后如果满足某些条件,您将在其位置创建另一个 TStringList
,完全忽略第一个。因此,内存泄漏。
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;
"The stringlists are never freed"
我希望这不是设计使然。您创建的所有内容都必须在某个时候被释放,尤其是当您拥有创建其结果的函数时。唯一的例外是,如果您创建的东西在应用程序的整个持续时间内都存在,即使如此,无论如何释放它们也是极端的共同点。
关于这一点,我唯一一次在函数结果中创建对象是在封装多行代码时,否则这些代码会被重复多次。例如,创建查询。
与其重复此代码...
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;
The stringlists are never freed
这本身就是一个问题。就像评论中提到的那样,这会造成内存泄漏。总的来说,我不赞成创建对象并通过其结果赋予所有权的函数。当我需要这样做时,我通常将我的函数命名为 "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" 到 return 一个 TStringList 并且不想通过参数接收一个,请参阅此处如何正确管理它以避免内存泄漏。
function CreateAndInitStrings : TStringList;
begin
Result := TStringList.Create;
try
if someConditionIsTrue then
doSomething(Result);
//other code
except
Result.Free;
raise;
end;
end;
假设我有一个函数:
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;
如果我 运行 此代码一切正常,但我仍然想知道这是否是 "proper" 传递对象(如字符串列表)的方法?
字符串列表永远不会被释放,我想知道在调试或其他试图理解代码的人时,以这种方式传递对象是否会变得复杂或混乱。
"proper" 方法是让您建立自己的销毁规则。在函数结果中创建对象很好,但前提是您要遵循自己的严格规则。
在您的情况下,SomeFunction
存在内存泄漏。首先,您创建一个 TStringList
,然后如果满足某些条件,您将在其位置创建另一个 TStringList
,完全忽略第一个。因此,内存泄漏。
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;
"The stringlists are never freed"
我希望这不是设计使然。您创建的所有内容都必须在某个时候被释放,尤其是当您拥有创建其结果的函数时。唯一的例外是,如果您创建的东西在应用程序的整个持续时间内都存在,即使如此,无论如何释放它们也是极端的共同点。
关于这一点,我唯一一次在函数结果中创建对象是在封装多行代码时,否则这些代码会被重复多次。例如,创建查询。
与其重复此代码...
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;
The stringlists are never freed
这本身就是一个问题。就像评论中提到的那样,这会造成内存泄漏。总的来说,我不赞成创建对象并通过其结果赋予所有权的函数。当我需要这样做时,我通常将我的函数命名为 "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" 到 return 一个 TStringList 并且不想通过参数接收一个,请参阅此处如何正确管理它以避免内存泄漏。
function CreateAndInitStrings : TStringList;
begin
Result := TStringList.Create;
try
if someConditionIsTrue then
doSomething(Result);
//other code
except
Result.Free;
raise;
end;
end;