2016-07-05 117 views
-1

假设我有一个功能:如何在函数之间传递对象?

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; 

如果我运行此代码一切正常如愿,但我仍然不知道这是否是“正确的”方式来传递一个对象像一个字符串列表?

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

+1

您已经在第一个代码示例中单独发生了内存泄漏,甚至没有在其他任何地方使用它。首先你创建一个实例,然后你完全忽视这个实例,并创建另一个实例。 –

+0

您的代码正在创建2个TStringlist实例,这会导致内存泄漏。而某个函数返回的那个会根据'someConditionIsTrue'的值而有所不同。哎呀,你不需要创造一些东西。 – MartynA

+0

没有“适当”的方式。你需要制定关于**哪一方可以释放记忆**的约定,并严格遵守它。另外,您需要关注编译器提示,它会向您指出第一个代码段的问题。 –

回答

6

“正确”的方法是让你建立你自己的规则,如何销毁。在函数结果中创建对象是很好的,但前提是你遵循自己的严格规则。

在你的情况下,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; 

“的stringlists是永远不会被释放”

我希望这不是设计。你创建的所有东西都必须在某个时候被释放,特别是如果你有能够创建结果的功能。唯一的例外是,如果您创建的应用程序在整个应用程序中都存在,并且无论如何都是非常普遍的。


关于这一点,我曾经在创建一个函数结果确定目标的唯一时间是当我封装的,否则被多次复制多行代码。例如,创建一个查询。

而不是重复这个代码...

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

我记得你给我提供了一个很好的回答,我几年前问过的一个问题。所以,再次感谢您的回应: - ] –

+0

在创建对象后引发异常的CreateQuery泄漏 –

+0

@David确实,尽管只是一个非常原始且最小的代码示例。 –

6

的stringlists从不释放

这本身就是一个问题。就像在评论中提到的一样,这造成了内存泄漏。总的来说,我对创建对象并通过结果赋予所有权的函数感到不满。当我需要这样做时,我通常会命名我的函数"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; 
+0

Err,imo'procedure someFunction'是不幸的;也许'程序NotActuallyaFunction'。 – MartynA

+0

我保持与问题中相同的语义,以使对应尽可能的清晰。 –