web-dev-qa-db-ja.com

shared_ptrを参照渡しする必要がありますか?

Shared_ptrを渡すためのベストプラクティスは何ですか?

現在、shared_ptr関数の引数を次のように渡します。

void function1( shared_ptr<TYPE>& value );
89
Ben Crowhurst

制御された環境では、定数参照で共有ポインタを渡すことができます。オブジェクトを同時に削除している人がいないことを確認してください。ただし、参照を与える相手に注意を払えば、これはそれほど難しくないはずです。

一般に、共有ポインターをストレートcopyとして渡す必要があります。これにより、意図したセマンティクスが得られます。共有ポインタのコピーを含むすべてのスコープは、所有権の「共有」によってオブジェクトを存続させます。

常に値渡しをしない唯一の理由は、共有ポインタをコピーすると、アトミックな参照カウントの更新のために一定の価格がかかるためです。ただし、これは大きな問題ではないかもしれません。


オプションの余談:

主な質問が回答されたので、おそらくnever共有ポインタを使用するいくつかの方法を検討することは有益です。ここに少し考えられた実験があります。共有ポインタータイプSF = std::shared_ptr<Foo>を定義しましょう。参照を考慮するために、関数の引数を渡すのではなく、RSF = std::reference_wrapper<T>型を見てみましょう。つまり、共有ポインターSF p(std::make_shared<Foo>());がある場合、RSF w = std::ref(p);を介して値のセマンティクスを使用して参照ラッパーを作成できます。セットアップはこれで終わりです。

今、誰もがポインタのコンテナが地雷原であることを知っています。したがって、std::vector<Foo*>は維持するのが悪夢であり、不適切なライフタイム管理から多くのバグが発生します。概念的に悪いのは、コンテナが格納するポインタを持つオブジェクトの所有者ownsが明確ではないことです。ポインターは、動的オブジェクト、自動オブジェクト、およびガベージへのポインターの混合でさえありえます。誰にもわかりません。したがって、標準的な解決策は、代わりにstd::vector<SF>を使用することです。これは、共有ポインタを使用する正しい方法です。一方、絶対に使用してはならないのはstd::vector<RSF>です。これは、管理されないモンスターであり、実際にはネイキッドポインターの元のベクトルに非常によく似ています。たとえば、参照を保持するオブジェクトがまだ生きているかどうかは明確ではありません。共有ポインターの参照を取得すると、その目的全体が無効になります。

2番目の例として、以前のように共有ポインターSF pがあるとします。これで、同時に実行したいint foo(SF)関数ができました。スレッドコンストラクターは引数のcopyを作成するため、通常のstd::thread(foo, p)は正常に機能します。ただし、std::thread(foo, std::ref(p))と言った場合、あらゆる種類の問題が発生します。呼び出しスコープ内の共有ポインターが期限切れになり、オブジェクトが破壊される可能性があります。

共有ポインタをcopyで渡したい場合、これらの2つの例が明らかにかなり工夫されていることで少し光を当てることを願っています。適切に設計されたプログラムでは、誰がどのリソースを担当するかが常に明確である必要があります。また、適切に使用される場合、共有ポインターは仕事に最適なツールです。

95
Kerrek SB

それはあなたが望むものに依存します。呼び出し先はオブジェクトの所有権を共有する必要がありますか?次に、shared_ptrの独自のコピーが必要です。したがって、値で渡します。

関数が単に呼び出し元が所有するオブジェクトにアクセスする必要がある場合は、shared_ptrをコピーするオーバーヘッドを回避するために、先に進んで(定数)参照を渡します。

C++でのベストプラクティスは、オブジェクトの所有権セマンティクスを明確に定義することですalways。実際のthoughtを置き換える普遍的な「常にこれを行う」というものはありません。

always共有ポインタを値で渡すと、コストがかかります(生のポインタよりもコピーするのがはるかに高価だからです)。 neverを行うと、そもそも共有ポインタを使用しても意味がありません。

新しい関数またはオブジェクトが指示先の所有権を共有する必要がある場合、共有ポインタをコピーします。

25
jalf

参照渡しする場合は、const参照渡しします。これにより、パフォーマンス上の理由からrefを渡していることが明らかになります。また、可能な場合はmake_sharedを使用します。これは、インダイレクションを保存するため、パフォーマンスが向上します。

8
Kate Gregory