web-dev-qa-db-ja.com

C ++:「参照渡し」の引数渡し

他の変数と同様に、パラメーターのタイプがパラメーターとその引数の間の相互作用を決定することを理解しています。私の質問は、パラメーターを参照する理由とそうでない理由の背後にある理由は何ですか?一部の関数パラメーターが参照され、一部が参照されないのはなぜですか?そうすることの利点を理解するのに苦労していますが、誰か説明できますか?

20
Tyler

この記事は私を大いに助けてくれました。

現時点ではポインタを忘れてください。そして、これを塩の粒で取ります。

参照isオブジェクト。参照渡しの場合、theオブジェクトを渡します。

値で渡すときは、オブジェクトのcopyを渡します。 anotherオブジェクト。同じstateを持つこともありますが、differentインスタンスです。クローン。

したがって、次の場合は参照渡しするのが理にかなっています。

  • 変更する必要がありますthe関数内のオブジェクト
  • theオブジェクトを変更する必要はありません(またはしたくない)が、関数に渡すためだけにコピーすることは避けたいです。これはconst参照になります。

また、次の場合は値で渡すのが理にかなっています。

  • identicaltwinから開始し、original twinをそのまま残したい
  • オブジェクトのコピーのコストを気にしません(たとえば、参照によってintを渡しませんnless変更したい場合)。

ここで、このコードを見てください:

#include<iostream>

struct Foo {
  Foo() { }
  void describe() const {
    std::cout<<"Foo at address "<<this<<std::endl;
  }  
};

void byvalue(Foo foo) {
  std::cout<<"called byvalue"<<std::endl;
  foo.describe();
}

void byreference(Foo& foo) {
  std::cout<<"called byreference"<<std::endl;  
  foo.describe();
}

int main() {
  Foo foo;
  std::cout<<"Original Foo"<<std::endl;
  foo.describe();
  byreference(foo);
  byvalue(foo);
}

次のようにコンパイルします:g++ example.cpp

実行:./a.out

出力を確認します(実際のアドレスはコンピューターによって異なる場合がありますが、ポイントは残ります)。

Original Foo
Foo at address 0x7fff65f77a0f
called byreference
Foo at address 0x7fff65f77a0f
called byvalue
Foo at address 0x7fff65f779f0

called byreferenceアドレスがOriginal Fooアドレスと同じであることに注意してください(両方とも0x7fff65f77a0fです)。 called byvalueアドレスがdifferent0x7fff65f779f0)であることに注意してください。

ノッチを上げます。コードを次のように変更します。

#include<iostream>
#include<unistd.h> // for sleeping

struct Foo {
  Foo() { }
  Foo(const Foo&) {
    sleep(10); // assume that building from a copy takes TEN seconds!
  }
  void describe() const {
    std::cout<<"Foo at address "<<this<<std::endl;
  }  
};

void byvalue(Foo foo) {
  std::cout<<"called byvalue"<<std::endl;
  foo.describe();
}

void byreference(Foo& foo) {
  std::cout<<"called byreference"<<std::endl;  
  foo.describe();
}

int main() {
  Foo foo;
  std::cout<<"Original Foo"<<std::endl;
  foo.describe();
  byreference(foo);
  byvalue(foo);  
}

同じ方法でコンパイルし、出力を確認します(出力にはないコメント。わかりやすくするために含まれています)。

Original Foo
Foo at address 0x7fff64d64a0e
called byreference
Foo at address 0x7fff64d64a0e # this point is reached "immediately"
called byvalue # this point is reached TEN SECONDS later
Foo at address 0x7fff64d64a0f

そのため、コードはコピーのコストを誇張することを目的としています。参照で呼び出した場合、このコストは発生しませんでした。値で呼び出した場合、10秒待つ必要がありました。

注:私のコードは、GCC 4.8.1を使用してOS X 10.7.4でコンパイルされました。 Windowsを使用している場合、sleep呼び出しを機能させるには、unitsd.hとは異なるものが必要になる場合があります。

たぶんこれが役立ちます。

23
Escualo

参照によっても、ポインターによって変数を手動で渡すことと同じですが、参照によって、ユーザーが「混乱しやすい」ポインターを処理することはできません。

1
TerrenceSun

参照渡しを使用する長所:メモリ内のデータへのポインタのみを渡すデータのコピーを作成する必要はありません。 (巨大なパフォーマンスの勝利は、あなたが渡した巨大なオブジェクトを持っているかどうかを考えてください)。複数の値を「返す」ことができます。c/ c ++の一部の関数は数値を返し、paramsの1つは操作されるデータへのポインターです。

参照渡しを使用する場合の短所:渡されるデータは、必要な場合とそうでない場合があるため、注意して変更する必要があります。

1
dbarnes