2

一般的な質問として、関数のシグネチャは次のとおりです。

void f( const string & s )...

実際に文字列を変更していないのに、なぜこれを参照渡しする必要があるのでしょうか (文字列は定数であるため)。

4

5 に答える 5

6

参照渡しには、ポインター渡しと値渡しの 2 つの方法があります。

ポインターによる受け渡しは、参照による受け渡しと似ています。「ポインターを変更したくないのになぜポインターを渡すのか」という同じ議論がそれに対して行われる可能性があります。

値渡しには、コピーを作成する必要があります。文字列のコピーは通常、動的メモリの割り当てと割り当て解除を裏で行う必要があるため、よりコストがかかります。constそのため、変更する予定のないコピーを渡すよりも、参照/ポインターを渡す方がよい場合がよくあります。

于 2013-10-07T00:52:16.233 に答える
3

変数を値で渡すと、コピーが作成されます。参照渡しにより、そのコピーが回避されます。マークを付けたいconstのは同じ理由です。コピーを作成していないので、誤ってオリジナルを台無しにしたくありません。これにより、コンパイラの最適化も可能になる可能性があると思います。

intchar、 、およびその他のプリミティブ型でこれが通常見られない理由はfloat、コピーするのが比較的安価であり、場合によっては、参照渡しのほうがコストがかかるからです (たとえば、char参照渡しでは 64 を渡す必要がある場合があります)。 8 ビットの代わりに - ビットのデータ (ポインタ) 参照渡しはまた、文字列のような大きな型では大したことではありませんが、int.

于 2013-10-07T00:50:23.907 に答える
1

「必要」ではありませんが、一般的な答えは「パフォーマンス上の理由から、コピーを防ぐため」ですが、それは素朴な答えであり、真実はもう少し複雑です。

sあなたの例では、実際には不変であり、「所有していない、または変更できない」ものであると仮定すると、constデコレータはs. の参照がs取得されなかった場合は、コピーが保証されます (コンパイラの最適化を除く)。

返品後f()のコピーを使用しない場合、コピーの労力が無駄になります。そのため、参照渡しによりコピーが防止され、文字列を検査する機能が保持されます。偉大な。繰り返しますが、それは素朴な答えであり、C++ 11より前のものがほとんど正しい答えです。sf()sf()s

「それが必要か?」に答えるために検討する価値のあるシナリオは他にもあります。しかし、私は1つだけに焦点を当てます:

の呼び出し元が の呼び出し後に f()文字列を必要としないが、データのコピーを保持する必要がある場合。sf()f()

コードは次のとおりです。

void f(const std::string& arg1);   // f()'s signature
void g(const std::string& arg1) {
   std::string s(arg1);
   s.append(" mutate s");
   f(s);
}

この場合、 string を構築し、参照sによって に渡します。 が不透明であり、それ以上の最適化が利用できないと仮定すると、パフォーマンスの観点からはすべて問題ありません。constf()f()

f()では、 のデータのコピーが必要だとsします。さて、f()コピー コンストラクターを呼び出しsて、ローカル変数にコピーします。

 // Hypothetical f()
 void f(const std::string& s) {
   this->someString_ = s;
 }

この場合、データが に格納されるまでにsomeString_、 では通常のコンストラクタが呼び出されg()、 ではコピー クタが呼び出されますがf()、 で行われた作業はg()無駄になります。パフォーマンスを向上させるには、値渡しおよび/またはムーブ コンストラクターの使用という 2 つの方法があります。

// Explicitly move arg1 in to someString_
void f(std::string&& arg1) {
  this->somestring_ = std::move(arg1);
}

void g(const std::string& arg1) {
   std::string s(arg1);
   s.append(" mutate s");
   f(s);
}

これは、コンパイラが自動的に から開始することを明示的に行っていますC++11。つまり、より正しいバージョンは、値で渡し、コンパイラに正しいことをさせることです。

void f(std::string arg1) {
  this->somestring_ = arg1; // Implicit move, let the compiler do the right thing
}

void g(const std::string& arg1) {
   std::string s(arg1);
   s.append(" mutate s");
   f(s);
}

この場合、文字列は で構築されg()、追加の作業はどこにも行われません。したがって、この場合の答えは、

実際に文字列を変更していないのに、なぜこれを参照渡しする必要があるのでしょうか (文字列は定数であるため)。

文字列は変更されていませんが、コピーされているため、const 参照は必要ありませんでした。

sへの呼び出し後に変更されている場合と変更されていない場合に、コンパイラが実行できる最適化を一覧表示するのは、読者の課題f()です。

David Abrams の投稿「スピードが欲しいですか? 値渡し' またはC++ では、値渡しと定数参照渡しのどちらが優れていますか? C++ でオブジェクトを関数に渡す方法を投稿しますか? .

于 2013-10-07T05:02:12.137 に答える