スマートポインター (shared_ptr) を参照または値で返すにはどうすればよいでしょうか? 質問する

スマートポインター (shared_ptr) を参照または値で返すにはどうすればよいでしょうか? 質問する

を返すメソッドを持つクラスがあるとしますshared_ptr

参照または値で返すことの利点と欠点は何ですか?

考えられる手がかりは2つあります:

  • 早期のオブジェクト破壊。by (const) 参照を返すとshared_ptr、参照カウンターは増加しないため、別のコンテキスト (別のスレッドなど) でスコープ外になったときにオブジェクトが削除されるリスクがあります。これは正しいですか? 環境がシングルスレッドの場合、この状況も発生する可能性がありますか?
  • 料金。値渡しは確かに無料ではありません。可能な限りそれを避ける価値はあるでしょうか?

みなさんありがとう。

ベストアンサー1

スマート ポインターを値で返します。

おっしゃるとおり、参照で返すと、参照カウントが適切に増加しないため、不適切なタイミングで何かが削除されるリスクが生じます。これだけでも、参照で返さない十分な理由になります。インターフェイスは堅牢である必要があります。

コストの懸念は今日では意味をなさない。戻り値の最適化(RVO) を使用すると、最新のコンパイラでインクリメント-インクリメント-デクリメント シーケンスなどが発生することはありません。したがって、 a を返す最良の方法は、shared_ptr単に値を返すことです。

shared_ptr<T> Foo()
{
    return shared_ptr<T>(/* acquire something */);
};

これは、最新の C++ コンパイラーにとって、RVO の明らかなチャンスです。Visual C++ コンパイラーは、すべての最適化がオフになっている場合でも RVO を実装していることは事実です。また、C++11 の移動セマンティクスでは、この懸念はさらに無関係です。(ただし、確実に知る唯一の方法は、プロファイルして実験することです。)

まだ納得できないなら、デイブ・エイブラハムズが記事値を返すことの根拠となる部分です。ここで抜粋を転載しますが、記事全体を読むことを強くお勧めします。

正直に言って、次のコードを見てどう感じますか?

std::vector<std::string> get_names();
...
std::vector<std::string> const names = get_names();

正直に言うと、もっとよく知っておくべきなのに、不安になります。原則として、get_names()が戻るとき、vectorのをコピーする必要がありますstring。次に、 を初期化するときにもう一度コピーする必要がありnames、最初のコピーを破棄する必要があります。ベクトルに N 個ある場合string、文字列の内容がコピーされるたびに、コピーごとに N+1 個のメモリ割り当てと、キャッシュに適さない大量のデータ アクセスが必要になる可能性があります。

そのような不安に立ち向かうよりも、私は不必要なコピーを避けるために参照渡しに頼ることが多いです。

get_names(std::vector<std::string>& out_param );
...
std::vector<std::string> names;
get_names( names );

残念ながら、このアプローチは理想からは程遠いものです。

  • コードは150%増加しました
  • const名前を変更しているため、-ness を削除する必要がありました。
  • 関数型プログラマーがよく思い出させてくれるように、突然変異は参照の透明性と等式による推論を損なうため、コードの推論をより複雑にします。
  • 名前に対して厳密な値セマンティクスはなくなりました。

しかし、効率を上げるためにこのようにコードを台無しにすることが本当に必要なのでしょうか? 幸いなことに、答えは「いいえ」です (特に C++0x を使用している場合はそうではありません)。

おすすめ記事