[解決済み] const std::string & をパラメータとして渡す時代は終わったのでしょうか?
質問
最近、ハーブ・サッターの講演を聞いたのですが、彼が言うには、パスする理由は
std::vector
と
std::string
によって
const &
はほとんどなくなりました。 以下のような関数を書くのが今は望ましいと提案した。
std::string do_something ( std::string inval )
{
std::string return_val;
// ... do stuff ...
return return_val;
}
というのはわかりますが
return_val
は関数が戻った時点で rvalue になるので、move セマンティクスを使用して返すことができ、これは非常に安価です。 しかし
inval
は、参照(通常ポインタとして実装される)のサイズよりもはるかに大きいままです。 というのも
std::string
は、ヒープへのポインタやメンバーである
char[]
短い文字列の最適化のためです。 ということで、やはり参照渡しが良いようです。
なぜハーブがこのようなことを言ったのか、説明できる人はいますか?
解決方法は?
ハーブの発言は、このようなケースを想定してのものです。
例えば
A
を呼び出し、関数
B
という関数が呼び出されます。
C
. そして
A
は文字列を
B
と
C
.
A
を知らないし、気にもしていない。
C
すべて
A
が知っているのは
B
. ということです。
C
の実装詳細です。
B
.
Aは次のように定義されているとしよう。
void A()
{
B("value");
}
によってBとCが文字列を取ると
const&
とすると、次のような感じになります。
void B(const std::string &str)
{
C(str);
}
void C(const std::string &str)
{
//Do something with `str`. Does not store it.
}
順調でよろしい。ポインターを受け渡すだけで、コピーも移動もなく、みんなハッピーです。
C
を取ります。
const&
は文字列を保存しないためです。なぜなら、文字列を保存せず、単にそれを使用するからです。
さて、1つだけ簡単な変更を加えたいと思います。
C
は、文字列をどこかに保存する必要があります。
void C(const std::string &str)
{
//Do something with `str`.
m_str = str;
}
こんにちは、コピーコンストラクタと潜在的なメモリ割り当て(無視してください。
短い文字列の最適化 (SSO)
). C++11のmoveセマンティクスは、無駄なコピーコンストラクトを削除できるようにするものですよね?そして
A
はテンポラリを渡します。
C
が必要です。
コピー
を作成します。与えられたデータをそのまま持ち去ればいいのです。
ただし、それはできない。なぜならそれは
const&
.
を変更すると
C
を値で受け取るようにした場合、それは単に
B
を使うと、そのパラメータにコピーが行われるため、何も得るものがありません。
ということは、もし私が
str
を値としてすべての関数を通過させます。
std::move
でデータをシャッフルすれば、こんな問題は起きないはずです。誰かがそれを持ち続けたいと思えば、持ち続けることができます。そうでないなら、まあいいや。
コストが高い?はい。値に移動することは、参照を使用するよりもコストがかかります。コピーよりも安価ですか?SSOのある小さな文字列の場合は、そうではありません。やる価値があるか?
ユースケースによります。メモリ割り当てをどの程度嫌うか?
関連
-
[解決済み】C++でランダムな2倍数を生成する
-
[解決済み】C++ 式はポインタからオブジェクトへの型を持っている必要があります。
-
[解決済み] error: 'if' の前に unqualified-id を期待した。
-
[解決済み] クラスにデフォルトコンストラクタが存在しない。
-
[解決済み】c++でstd::vectorを返すための効率的な方法
-
[解決済み】警告 - 符号付き整数式と符号なし整数式の比較
-
[解決済み] std::string を const char* または char* に変換する方法
-
[解決済み] 文字列の単語を反復処理するにはどうすればよいですか?
-
[解決済み] const int*、const int * const、int const *の違いは何ですか?
-
[解決済み] std::stringのインスタンスを小文字に変換する方法
最新
-
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 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み】コンストラクターでのエラー:識別子を期待されますか?
-
[解決済み】文字列関数で'char const*'のインスタンスを投げた後に呼び出されるterminate [閉店].
-
[解決済み】IntelliSense:オブジェクトに、メンバー関数と互換性のない型修飾子がある
-
[解決済み】エラー。switchステートメントでcaseラベルにジャンプする
-
[解決済み】Visual C++で "Debug Assertion failed "の原因となる行を見つける。
-
[解決済み] [Solved] インクルードファイルが開けません。'stdio.h' - Visual Studio Community 2017 - C++ Error
-
[解決済み] 配列のベクトルを扱う正しい方法
-
[解決済み】'std::cout'への未定義の参照
-
[解決済み] C++のPOD型とは何ですか?
-
[解決済み] std::stringの文脈における頭文字SSOの意味