如何在函数之间传递对象?

时间:2016-07-05 17:16:06

标签: delphi object lazarus

假设我有一个功能:

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这样的对象的“正确”方法?

字符串列表永远不会被释放,我想知道在调试或其他人试图理解代码时,以这种方式传递对象会变得复杂或混乱。

2 个答案:

答案 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;