2016-07-05 113 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

我保持與問題中相同的語義,以使對應儘可能的清晰。 –