2016-07-05 7 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インスタンスを作成しています。これによりメモリリークが発生します。 someFunctionによって返されるものは、 'someConditionIsTrue'の値によって異なります。あなたはdoSomethingの.Createは必要ありません。 – MartynA

+0

"適切な"方法はありません。あなたは**どのパーティーがメモリ**を解放し、厳密にそれに従うかについてのあなたの大会を開発する必要があります。また、コンパイラのヒントに注意する必要があります。最初のスニペットの問題を指摘します。 –

答えて

6

「適切な」アプローチは、物事がどのように破壊されるかについての独自のルールを確立することです。関数の結果にオブジェクトを作成しても問題ありませんが、厳密な規則に従っている場合に限ります。

あなたの場合、SomeFunctionにメモリリークがあります。まず、TStringListを作成し、条件が満たされた場合は、最初のものを完全に無視して別のTStringListを作成します。したがって、メモリが漏れています。

DoSomethingは、すでに文字列リストが作成されている可能性がある場合は、文字列リストを返す関数であってはなりません。

function someFunction: TStringList; 
begin 
    Result:= TStringList.Create; 
    if someConditionIsTrue then 
    DoSomething(Result); 
    //other code 
end; 

"stringlistsが解放されることはありません"

Iを:あなたは、その後SomeFunctionは次のようになり、それを行うたら代わりに、ちょうど...それ手順

procedure DoSomething(AList: TStringList); 
begin 
    AList.Add(Something); 
end; 

を作りますこれは設計によるものではないことを望みます。あなたが作成するすべてのものは、特にその結果を作成する関数を持っている場合、ある時点ではfree'dでなければなりません。唯一の例外は、アプリケーションの全期間生存しているものを作成していても、とにかくそれらを解放するための極端な共通点です。そのノートオン


私はそう何回も複製されます複数行のコードをカプセル化していたときに、私が今まで関数の結果でオブジェクトを作成するだけです。たとえば、クエリを作成します。代わりにこのコードを繰り返し

...

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は決してありません解放された

これはどれも問題です。 Likeはコメントで言及され、メモリリークを引き起こします。一般的に、私はオブジェクトを作成し、その結果を通して所有権を与える関数に目を向けます。私がそうする必要があるときは、通常、私の関数の名前を"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; 

あなたが本当にTStringListのを返すために、あなたの「someFunction」が必要とパラメータを通じて1を受信したくない場合は、ここではメモリリークを避けるために適切に管理する方法を説明します。

function CreateAndInitStrings : TStringList; 
begin 
    Result := TStringList.Create; 
    try 
    if someConditionIsTrue then 
     doSomething(Result); 
    //other code 
    except 
    Result.Free; 
    raise; 
    end; 
end; 
+0

Err、imo '手続きsomeFunction'は残念です。多分 'プロシージャNotActuallyaFunction'です。 – MartynA

+0

私は質問と同じセマンティックを維持して、対応をできるだけ明示的にしました。 –

関連する問題