web-dev-qa-db-ja.com

C ++では、すべての関数パラメーターを参照にする必要がないのはなぜですか?

私は現在、C++ Primer 5th editionからC++を学んでいます。関数に関する本の章では、ラージオブジェクト(大きいものは標準ライブラリ文字列として相対的であるが、intやcharなどの「プリミティブ型」は対象外)のみを参照として渡すべきであると述べています。

たとえば、次の関数は、参照パラメーターをいつ使用するかの本の例として機能します。

string::size_type find_char(const string &s, char c, string::size_type &occurs){
    /* code to return the first occurrence of c in s, occurs contains total number of occurrences */
}

演習の1つでは、各パラメーターの根拠が、ベースタイプの範囲を超えているかどうかを尋ねます。文字列が参照である理由(コピーを防止してパフォーマンスを向上させるため)および文字列がconstである理由(変更する必要がないため)を理解しています。 occursパラメーターが参照である理由も理解しています(元の変数の値を変更する必要があるため)。

私が理解していないのは、cが(const)参照ではない理由です。非常に小さなオブジェクトが含まれていることはわかっていますが、オブジェクトがコピーされないようにしても、どれほど小さくてもパフォーマンスは向上しますか?

参照の使用にいくつかの欠点がある場合、それは理にかなっています。しかし、私はそのようなマイナス面が何であるかを知りません。また、私はポインタのアドレスがコピーされることを知っていますが、参照は変更できないので、呼び出された関数は呼び出し元が行うのとまったく同じ方法で元の変数にアクセスできると想像します(変数が発信者)。

変更された値を返さずに関数の実装用にパラメーターを変更する必要がない限り、特に上記の例のようなインスタンスで、非参照パラメーターを使用する必要があるのはなぜですか?

注:関数本体は本に含まれていますが、簡潔にするためにこの質問から削除されています。

7
john01dav

基本タイプの場合、参照パラメーターは通常、パフォーマンス属性をまったく提供しません。

メモリ

たとえば、あなたの例では、charには1バイトが必要です。参照タイプには、通常4または8バイトのポインターが必要です。ポインターのサイズは、サイズにより、使用している実行可能ファイルのタイプ(32ビットの場合は4バイト、64ビットの場合は8バイト)に直接相関します。メモリレジスタの。

最近のほとんどのマシンでは、これはスタック上またはレジスター内で単一の値として渡されます。ですから、まったく違いはありません。

時間

基本的なタイプ(charintlong)のコピーは通常、単一のMOV命令です。参照パラメーターで使用されるポインターの設定も、通常、単一のMOV命令です。

8
Gort the Robot

参照の使用には2つの欠点があります。

  1. 参照を使用すると、エイリアスを追加できます。つまり、コンパイラーは、他の方法で、コード内の2つの使用法の間で値が読み書きされないと判断できない限り、より頻繁に値を再ロードして保存する必要があります。

  2. すべての間接参照は、メモリの追加読み取りを意味します。

多くの場合、これらの2つの効果は、型がポインターよりわずかに大きい場合でも、引数をコピーする必要がないことによる潜在的な節約を支配します。ポインタより大きくない簡単にコピーできる型には、そのような節約はありません。

余談ですが、C++ 17以降では、const std::string&std::string_view

後者は文字列を割り当てず、間接指定を減らし、割り当てポリシーがないため、より柔軟で効率的です。

8
Deduplicator