1. ホーム
  2. c++

[解決済み] const std::string & をパラメータとして渡す時代は終わったのでしょうか?

2022-03-15 06:02:10

質問

最近、ハーブ・サッターの講演を聞いたのですが、彼が言うには、パスする理由は std::vectorstd::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 は文字列を BC . 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のある小さな文字列の場合は、そうではありません。やる価値があるか?

ユースケースによります。メモリ割り当てをどの程度嫌うか?