2011-06-21 1 views
0

boost::shared_ptrの前に、呼び出し元がそのオブジェクトfree()を覚えておく必要があるので、関数からヒープ割り当てポインタを返すのは悪い習慣と考えられましたか?関数からヒープ割り当てポインタを返すのは悪いマナーですか?

または、「正常」とみなされましたか?

+4

[c]タグと 'boost :: shared_ptr'? –

+1

答えの大半は "C"ではなく "C++"ではなく、両方をカバーするので、将来の参照のために "c"タグを残しておくべきだと思います。私は、この問題を、CとC++がどのようにリソース処理上の違いがあるかを明確に示すものとして解釈するべきだと思います。 – Matt

答えて

11

あなたのAPIがポインタで終わったときにクライアントコードが呼び出すことのできる同等のXXX_free(またはXXX_closeXXX_clearupなど)の機能を提供している限り、それは悪い習慣ではありません。

このように、ヒープオブジェクトの存続期間の責任が1か所で維持されるという意味で、一貫した対称APIを使用できます。

このアプローチは、より複雑なリソース解放にも適しています。たとえば、返されるポインタが動的に割り当てられた構造体に割り当てられ、その構造体に動的に割り当てられたメモリを指すメンバがある場合、クリーンアッププロシージャ全体をクライアントコードから隠す/抽象化することができます。

+1

C++に関するほとんどのお勧めの本は、丸い裸のポインタを渡すことを避けることを今推奨しています。値のセマンティクスを持つクラスでそのような詳細を非表示にします。 (これは、おそらくOPが 'shared_ptr'を述べたのであろうが、それは一般的な方法でその問題を解決しようとしている)。 –

+3

@Daniel:確か。しかし、OPは "C"という質問にタグを付けました。私はCの答えを出しています! –

+0

+1:「そうですね、一貫性のある対称的なAPIがあります」 – dolphy

0

これは、特定のオペレーティングシステムで異なるランタイムに対して構築されたライブラリを処理する唯一の方法であったため、今でも一般的です。たとえば、Windowsでは、複数のVC++ランタイムライブラリを1つの実行可能ファイルで共有するのは、オブジェクトの割り当てと廃棄の両方を含むライブラリがすべての独自のメモリ管理を担当する場合のみです。 shared_ptrなどのツールが実際に問題を引き起こす可能性があります。

通常、機能名やドキュメント(正しく実行された場合)は、これが起こっていることを明白にします。また、フリーコールを処理するために対応するDeleteXXX()関数を持つことも一般的でした。

0

一般的に、あなただけ

より一般的な明示的なcreate_blah()関数からポインタを返しますが、それがnullの場合、この関数によって割り当てられた、(ポインタへの)ポインタで渡すことです。

+0

ダブルポインタです。 ** blah – Andrei

+0

@Andrei、よくポインタへのポインタはまだポインタです;-) –

1

これを行う必要がある場合は、割り当てられたポインタを取り出して解放する独自の「フリー」関数を用意するのが一般的です。これにより、メモリを破壊する互換性のない無料の実装をユーザーが使用することを防ぐことができます。

2

あなたはあなたの質問にタグを付けました。Cでは非常に一般的です。 fopenFILE *を返します。これは、後でfcloseを呼び出して割り当てを解除する必要があります。

あなたがC++にタグを付けるつもりなら、それはより複雑です。旧式のコードベース(1990年代半ば以前)は、オブジェクトへの裸ポインタの周りを頻繁に通過しました。市販されているライブラリ全体は、そのパターンに基づいていました(BorlandのOWL、Microsoft MFC)。

1

両方の方法の例として、メモリを割り当てる関数とポインタを返す関数、または既に割り当てられた領域へのポインタを受け入れる関数があります。

インターフェイスが明確に文書化され、従われている限り、両方に対してポジティブとネガティブがあります。例えば、多くの他の人々が言及したように、割当て機能を提供するライブラリは、典型的には、削除機能を提供すべきである。あなたがクライアントとして、その空想的な関数でどのような方法でメモリを割り当てたのかわからないので、クライアント(クライアント)は、それを破壊するためにどのメソッドを使用すべきか分かりません。

一方、ストレージの割り当てについて心配する必要がある場合は、論理を複雑にすることができます。これは、予想される作業を実行するかどうかを判断し、そのストレージが依然として適切かどうかを判断し、メモリのの使用状況によっては、割り当ての詳細を隠すことで、その最適化をカプセル化するのにも役立ちます。

短い答えは:あなた次第です。本当に間違ったやり方は、何かを選ぶことであり、インターフェースに一貫性がないか不明瞭です。

0

実際には、より良いイディオム(COMインターフェイスで使用される)は、関数呼び出しの前に呼び出し元でポインタの作成を要求し、ダブルポインタを受け入れる関数を記述することです。

For example

 
    HRESULT CreateDevice(
     [in]   UINT Adapter, 
     [in]   D3DDEVTYPE DeviceType, 
     [in]   HWND hFocusWindow, 
     [in]   DWORD BehaviorFlags, 
     [in, out]  D3DPRESENT_PARAMETERS *pPresentationParameters, 
     [out, retval] IDirect3DDevice9 **ppReturnedDeviceInterface 
    ); 

ので、呼び出し側は、ポインタを作成し、割り当て関数を呼び出すための責任があり、そしてその解放関数を呼び出すことを忘れない可能性が高いです(COMの場合には、あなたが呼び出す必要があり

しかし、私はCreation/Destruction関数と二重ポインタを渡すことを組み合わせることは、オブジェクトを使用した後にヒープ割り当てオブジェクトを受信者に通知する良い方法ですと思います。私は破壊/関数を作成しますOliに同意

は破棄機能の存在の作成機能は、ちょうど彼らの上に消えないだろうから、これらのオブジェクト彼が得るという事実にAPIのユーザーを有効にする必要がありはるかに対称的であり、自分自身、そして彼ら(Destroy fcns)を呼び出す必要があります。

+0

そして、私はちょうどCOMを「より良い」と言いました:) – bobobobo

関連する問題