C++の基礎:関数のconst参照について学ぶ

提供: Support
移動先: 案内検索

概要

C/C++の関数を呼び出す際、関数のパラメータを値で渡すと、そのパラメータの値はコピーされます。そのパラメータのデータがint、floatなどの基本的な型であれば、コピーするサイズも比較的小さいためオーバーヘッドも少ないのですが、もしパラメータのデータが大きな複合型で構成されている場合、コピーするサイズも大きくなるため、より大きなオーバーヘッドが発生する可能性があります。例えば、name、mid name、surnameを結合する以下のような関数を例に考えてみましょう。

string fullname (string name, string midname, string surname)
{
  return name + " " + midname + " " + surname;
}

このfullname関数は、値渡しによって3つの文字列パラメータを受け取り、それらをスペース文字と連結した結果を返します。この使用例では、パラメータを値でバイパスして、関数は与えられた文字列の値をname、midname、surnameパラメータにコピーします。

このコピー操作は、関数が呼び出される度に行われます。この操作が複数回行われる場合、例えば、長い名前のリストからデータベースにフルネームを送信したり、データベースからフルネームを取得したりする場合、合計すると、関数の宣言と呼び出しのためだけに大量のデータをコピーしていることになります。これらのデータ型変数には、非常に長い文字列、構造体、ビットマップなどの場合もあり、コピーするサイズに応じて非常に大きいオーバーヘッドが生じます。このような使い方をすると、アプリケーションの動作が遅くなったり、同じメソッドやアルゴリズムを使用している他のアプリケーションと比べてパフォーマンスを大幅に低下させる原因となります。

&演算子を使用して両方のパラメータを参照するようにすれば、このコピーを完全に回避することができます。ここでは、以下のようにstring型の代わりにstring&を使用します。

string fullname (string& name, string& midname, string& surname)
{
  return name + " " + midname + " " + surname;
}

先に説明したように、参照によるパラメータはコピーを必要としません。 この関数は、パラメータとして渡された文字列アドレスを直接操作します。これは、ほとんどの場合、関数への特定のポインタの転送を意味します。 この点で、参照を使用するこのfullname()関数のバージョンは、値を取得するバージョンよりも効率的です。 この点で、参照を使用するこのfullname関数のバージョンは、値渡しを行っているfullname関数バージョンよりも効率的です。

また、このような参照パラメータを持つ関数は、一般的には「渡された引数を変更する関数」と認識されており、そのために参照パラメータが使われています。

関数の参照パラメータを変更されないようにするには、そのパラメータをconst修飾子として定義することで実現できます。この使い方は、関数がそのパラメータを変更できないことを保証するためのものです。定数のパラメータは、const修飾子を使用して定義できます。ここでは、string&の代わりに、以下のコード例のようにconst string&を使用できます。

string fullname (const string& name, const string& midname, const string& surname)
{
  return name + " " + midname + " " + surname;
}

この関数は、パラメータをconst参照として定義することによりパラメータを変更することを禁じられていますが、文字列の実際のコピーを作成することなく,参照(引数のエイリアス)としてその値にアクセスすることができます。その結果、const参照は、引数を値で渡すのと同様の機能を提供しますが、大きな型のパラメータの効率が向上します。 そのため、C ++では、複合型の引数に定数パラメータが非常によく使用されています。但し、基本的なデータ型では、効率に目立った違いはなく、場合によってはconst参照の方が効率が悪いこともあるため、注意が必要です。

関連情報