を返すメソッドを持つクラスがあるとします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 を使用している場合はそうではありません)。