C++ 関数宣言がある場合:
int func(const vector<int> a)
それを置き換えることは常に有益でしょうか
int func(const vector<int> &a)
a
後者は関数に渡すためにコピーを作成する必要がないので?
C++ 関数宣言がある場合:
int func(const vector<int> a)
それを置き換えることは常に有益でしょうか
int func(const vector<int> &a)
a
後者は関数に渡すためにコピーを作成する必要がないので?
一般的に、はい。大きなオブジェクトは常に参照渡しする必要があります (特に C を使用している場合は、それらへのポインターを渡す必要があります)。
あなたが考えているような効率という点では、ほとんどの場合そうです。通常、基本的な型または小さい型では、これが遅くなる場合があります (意図的に)。
// copy x? fits in register: fast
void foo(const int x);
// reference x? requires dereferencing on typical implementations: slow
void foo(const int& x);
しかし、これはとにかくインライン化では問題ではありません。さらに、自分で値によって入力することもできます。これは、一般的なテンプレート関数でのみ問題になります。
ただし、関数がデータの独自のコピーを取得するため、変換が常に有効であるとは限らないことに注意することが重要です。次の簡単な例を考えてみましょう。
void foo(const int x, int& y)
{
y += x;
y += x;
}
int v = 1;
foo(v, v); // results in v == 3
変換を行うと、次のものが得られます。
void foo(const int& x, int& y)
{
y += x;
y += x;
}
int v = 1;
foo(v, v); // results in v == 4
に書き込むことはできませんがx
、他の方法で書き込むことができるためです。これをエイリアシングと呼びます。あなたが与えた例にはおそらく問題はありませんが(グローバル変数はまだエイリアスになる可能性があります!)、原則として違いに注意してください。
最後に、とにかく独自のコピーを作成する場合は、パラメーター リストで作成してください。コンパイラは、特に C++11 の右辺値参照/移動セマンティクスを使用して、それを最適化できます。
ほとんどの場合、そのほうが効率的ですがfunc
、ベクトルの独自のコピーを作成し、とにかく何をするにも破壊的に変更する必要がある場合は、数行を節約して、言語にコピーを作成させることもできます。値渡しパラメーターとして暗黙的に。コンパイラは、呼び出し元が実際にベクトルのコピーを後で使用していない場合、コピーを省略できることを理解できる可能性があると考えられます。
正しい。参照を渡すと、コピーが回避されます。コピーが含まれていて、実際には必要ない場合は、参照を使用する必要があります。(値を変更するつもりがない場合は、元の操作で問題なく const 参照を使用するか、コピーではなく元の値を変更したいためです。非 const 参照を使用します。)
もちろん、これは関数の引数に限定されません。たとえば、次の関数を見てください。
std::string foo();
ほとんどの人は、この関数を次のように使用します。
std::string result = foo();
ただし、 を変更していない場合はresult
、次の方法の方がはるかに優れています。
const std::string& result = foo();
コピーは作成されていません。また、ポインターとは対照的に、参照は、によって返される一時foo()
が有効なままであり、範囲外に出ないことを保証します (一時へのポインターは危険ですが、一時への参照は完全に安全です)。
C++-11 標準では、移動セマンティクスを使用してこの問題を解決していますが、ほとんどの既存のコードはまだこの新しい機能を利用していないため、可能な限り参照を使用することを習慣にしてください。
また、一時的なものを参照にバインドするときは、一時的なライフタイムに注意する必要があることに注意してください。
const int& f(const int& x)
{ return x; }
const int& y = f(23);
int z = y; /* OOPS */
ポイントは、値が 23 のテンポラリの有効期間が にバインドされint
ている式の末尾を超えて延長されないため、 に代入しようとすると未定義の動作が発生することです (ダングリング参照のため)。f(23)
y
y
z
int
やのような POD タイプ (Plain Old Data) を扱っている場合char
、コピーを回避しても何も得られないことに注意してください。通常、参照はint
orと同じ大きさlong int
(通常はポインタと同じ大きさ) であるため、参照によるコピーはそれ自体int
のコピーと同じです。int
要するに、はい。とにかく変更できないためa
、関数本体でできることは別のコピーを作成することだけです。これは const 参照から作成することもできます。
値渡しがより効率的であると想像できるいくつかの理由: