web-dev-qa-db-ja.com

スマートポインタを返すときのベストプラクティス

たとえばboost :: shared_ptrなどのスマートポインタを返すときのベストプラクティスは何ですか?標準で、スマートポインター、または基になる生のポインターを返す必要がありますか?私はC#から来ているので、それが正しいと感じるので、私は常にスマートポインタを返す傾向があります。このように(短いコードのconst-correctnessをスキップ):

class X
{
public:
    boost::shared_ptr<Y> getInternal() {return m_internal;}

private:
    boost::shared_ptr<Y> m_internal;
}

ただし、経験豊富なコーダーが生のポインターを返し、生のポインターをベクトルに入れるのを見てきました。それを行う正しい方法は何ですか?

31
Rolle

「正しい」方法はありません。それは本当に文脈に依存します。

スマートポインタを使用して内部的にメモリを処理し、外部から参照または生のポインタを与えることができます。結局のところ、インターフェイスのユーザーは、内部でメモリを管理する方法を知る必要はありません。同期コンテキストでは、これは安全で効率的です。非同期のコンテキストでは、多くの落とし穴があります。

どうすればよいかわからない場合は、スマートポインタを発信者に安全に返すことができます。参照数がゼロに達すると、オブジェクトの割り当てが解除されます。オブジェクトのスマートポインタを永久に保持するクラスがないことを確認してください。これにより、必要なときに割り当てが解除されなくなります。

最後の注意として、C++では、動的に割り当てられたオブジェクトを使いすぎないでください。ポインターを必要とせず、参照とconst参照で作業できる場合が多くあります。これはより安全で、メモリアロケータへのプレッシャーを軽減します。

23
Edouard A.

ポインタの意味によって異なります。

Shared_pointerを返すときは、構文的に「このオブジェクトの所有権を共有します」と言っているので、ポインターを解放する前に元のコンテナーオブジェクトが停止しても、そのオブジェクトは引き続き存在します。

生のポインタを返すと、「このオブジェクトについては知っていますが、所有していません」と表示されます。これは制御を渡す方法ですが、元の所有者に関連付けられた存続期間を維持することはできません。

(一部の古いcプログラムでは、「私を削除するのはあなたの問題です」という意味ですが、これは避けることを強くお勧めします)

通常、デフォルトで共有に設定すると、面倒な作業が大幅に軽減されますが、設計によって異なります。

11
Todd Gardner

関数にポインタ引数を渡し、ポインタを返すには、次のガイドラインに従います。

boost::shared_ptr

APIとクライアントはこのオブジェクトの所有権を共有しています。ただし、オブジェクトが何らかのグラフを表す場合は、shared_ptrでの循環参照を避けるように注意する必要があります。このため、shared_ptrの使用を制限しようとしています。

boost::weak_ptr / raw pointer

APIがこのオブジェクトを所有しているため、有効な間は共有できます。クライアントがapiよりも長生きする可能性がある場合は、weak_ptrを使用します。

std::auto_ptr

APIはオブジェクトを作成していますが、クライアントがオブジェクトを所有しています。これにより、返されるコードが例外安全であり、所有権が譲渡されていることが明確に示されます。

boost::scoped_ptr

スタックに格納されているオブジェクトへのポインタ、またはクラスメンバー変数としてのポインタ。最初にscoped_ptrを使用しようとします。

すべてのガイドラインと同様に、ルールが矛盾したり、曲げなければならない場合があるので、私はインテリジェンスを使用しようとします。

8
iain

私は通常、誰がクリーンアップの責任を負っているのかを明確にするために、工場などから「所有」/「一意の」スマートポインタを返します。

この例 https://ideone.com/qJnzva は、呼び出し元が値を割り当てる変数のスコープがスコープ外になったときに削除されるstd::unique_ptrを返す方法を示しています。

スマートポインターが自身のポインターを削除するのは事実ですが、スマートポインターを保持する変数の有効期間は呼び出し元によって100%制御されるため、呼び出し元はポインターがいつ削除されるかを決定します。ただし、これは「一意」で「所有」のスマートポインターであるため、他のクライアントは存続期間を制御できません。

7
Johann Gerell

生のポインターを返すことは決してありません。代わりに、weak_ptrを返して、ポインターのユーザーに、リソースを制御できないことを通知します。

Weak_ptrを返す場合、アプリケーションにダングリングポインタが存在する可能性はほとんどありません。

パフォーマンスの問題がある場合は、オブジェクトへの参照とhasValidXObjectメソッドを返します。

4
TimW

私の意見では、C++では、保護されていないポインターの使用を常に正当化する必要があります。

多くの正当な理由が考えられます。ポインタが格納している基になるデータ構造に問題があるため、非常に高いパフォーマンス、非常に低いメモリ使用量、レガシーライブラリの処理が必要です。しかし、[動的に割り当てられた]ポインタは、考えられるすべての実行パスでメモリの割り当てを解除する必要があり、ほぼ確実に1つを忘れるという点で、やや「悪」です。

3
Oliver N.

あなたの目標に依存します。

スマートptrを内部データに盲目的に返すことは良い考えではないかもしれません(これはあなたが解決しようとしているタスクに非常に敏感です)-代わりに内部でポインターを使用するいくつかのdoX()とdoY()を提供する方が良いかもしれません。

一方、スマートptrを返す場合は、オブジェクトが相互に破壊できなくなったときに相互循環参照を作成しないことも考慮する必要があります(その場合はweak_ptrの方が適している可能性があります)。

それ以外の場合は、前述のように、パフォーマンス/レガシーコード/ライフタイムの考慮事項をすべて考慮する必要があります。

0
deemok