[解決済み] スマートポインタ(shared_ptr)を参照または値で返すには?
質問
を返すメソッドを持つクラスがあるとします。
shared_ptr
.
参照で返すか値で返すか、考えられる利点と欠点は何ですか?
考えられる手がかりは2つです。
-
初期のオブジェクトの破壊。
を返すと
shared_ptr
を (const) 参照で返す場合、参照カウンタはインクリメントされないので、 別のコンテキスト (例えば別のスレッド) でスコープ外になったときにオブジェクトが削除される危険性があります。これは正しいのでしょうか?環境がシングルスレッドである場合、この状況は同様に起こり得るのでしょうか? - コストです。 パス・バイ・バリューは確かに無料ではありません。可能な限りそれを避ける価値があるでしょうか。
みなさん、ありがとうございます。
どのように解決するのですか?
スマートポインタを値で返します。
おっしゃるとおり、参照で返すと参照カウントが適切にインクリメントされないので、不適切なタイミングで何かを削除してしまう危険性が出てきます。それだけでも、参照で返さない十分な理由になるはずです。インターフェイスは堅牢であるべきです。
のおかげで、コストの懸念は最近では無意味になっています。
戻り値の最適化
(RVO) のおかげで、最近のコンパイラではインクリメント-インクリメント-デクリメントのシーケンスなどが発生しないので、コストの心配は無用です。というわけで、最適な返し方としては
shared_ptr
を返すには、単純に値で返すことです。
shared_ptr<T> Foo()
{
return shared_ptr<T>(/* acquire something */);
};
これは、最新のC++コンパイラにとって、死ぬほど明白なRVOの機会です。Visual C++ コンパイラーは、すべての最適化がオフの場合でも RVO を実装していることを私は知っています。また、C++11の移動セマンティクスでは、この懸念はさらに小さくなっています。(しかし、確かめる唯一の方法は、プロファイルして実験することです)。
まだ納得していないのであれば、Dave Abrahams が の記事 で、値で返すことについて論じています。ここではその一部を紹介しますが、記事全体を読むことを強くお勧めします。
正直なところ、次のコードを見てどう感じますか?
std::vector<std::string> get_names(); ... std::vector<std::string> const names = get_names();
正直なところ、よく分かっているはずなのに、不安になるのです。原則的には
get_names()
が返されると、私たちはvector
のstring
s. そして、初期化するときに再びコピーする必要があります。names
を初期化するときに再びコピーし、最初のコピーを破棄する必要がある。もし、N個のstring
がある場合、各コピーは がある場合、文字列の内容がコピーされるたびに、N+1 個ものメモリ割り当てと、キャッシュに適さないデータ アクセスが必要になる可能性があります。そのような不安に直面するよりもむしろ、私はしばしば参照渡しに戻って、不要なコピーを回避してきました。
get_names(std::vector<std::string>& out_param ); ... std::vector<std::string> names; get_names( names );
残念ながら、この方法は理想とは程遠いものです。
- コードは 150% 伸びました。
- を落とさなければならなくなりました。
const
-らしさは、名前を変異させるからです。- 関数型プログラマが私たちに思い出させるように、突然変異は参照透過性と等式推論を弱めることによって、コードを推論するのがより複雑になります。
- 名前に対する厳密な値のセマンティクスを持たなくなりました。
しかし、効率を上げるためにこのようにコードを混乱させることが本当に必要なのでしょうか?幸いなことに、答えは「いいえ」であることがわかりました (特に C++0x を使用している場合はそうではありません)。
関連
-
[解決済み] [Solved] Error C1083: Cannot open include file: 'stdafx.h'
-
[解決済み】#include<iostream>は存在するのですが、「識別子 "cout "は未定義です」というエラーが出ます。なぜですか?
-
[解決済み】CMakeエラー at CMakeLists.txt:30 (project)。CMAKE_C_COMPILER が見つかりませんでした。
-
[解決済み] 解決済み] `pthread_create' への未定義の参照 [重複] [重複
-
[解決済み】Eclipse IDEでC++エラー「nullptrはこのスコープで宣言されていません」が発生する件
-
[解決済み】c++で.txtファイルから2次元の配列に読み込む
-
[解決済み】shared_ptrは参照で渡すべきか、値で渡すべきか?
-
[解決済み】スマートポインタ(boost)の説明
-
[解決済み】C++のRAIIとスマートポインタ
-
[解決済み] クラスメンバにスマートポインタを使用する
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み】非静的メンバ関数への参照を呼び出す必要がある
-
[解決済み】C-stringを使用すると警告が表示される。"ローカル変数に関連するスタックメモリのアドレスが返される"
-
[解決済み】C++エラー:の初期化に一致するコンストラクタがありません。
-
[解決済み】C++の変数はイニシャライザーを持っているが、不完全な型?
-
[解決済み】オブジェクト引数のない非静的メンバ関数の呼び出し コンパイラーエラー
-
[解決済み】#include<iostream>は存在するのですが、「識別子 "cout "は未定義です」というエラーが出ます。なぜですか?
-
[解決済み】C++の余分な資格エラー
-
[解決済み】ファイルから整数を読み込んで配列に格納する C++ 【クローズド
-
[解決済み】システムが指定されたファイルを見つけられませんでした。
-
[解決済み】変数やフィールドがvoid宣言されている