ポインターと参照パラメーターの違いは?
-
05-07-2019 - |
質問
これらは同じですか:
int foo(bar* p) {
return p->someInt();
}
and
int foo(bar& r) {
return r.someInt();
}
ヌルポインターの可能性を無視します。これらの2つの関数は、 someInt()
が仮想であるか、または bar
または bar
のサブクラスが渡されるかどうかにかかわらず、機能的に同一ですか?
このスライスは何でもします:
bar& ref = *ptr_to_bar;
解決
C ++参照は、ポインターを使用して実装される標準では意図的に指定されていません。参照は、「同義語」に似ています。変数へのポインタよりも変数へ。このセマンティクスは、ポインターが状況によっては過剰であると認識できる場合に、コンパイラーに可能な最適化を開きます。
さらにいくつかの違い:
- 参照にNULLを割り当てることはできません。 これは重大な違いであり、 あなたが1つを好む主な理由 その他。
- 住所を取得するとき ポインタ、あなたはのアドレスを取得します ポインター変数。あなたが取るとき 参照のアドレス、あなたは得る 変数のアドレス 参照。
- 参照を再割り当てすることはできません。一度初期化されると、そのライフ全体にわたって同じオブジェクトを指します。
他のヒント
すべての構文糖と、一方ではでき、他方ではできない可能性、および他の回答で説明されているポインターと参照の違いを無視します(他の質問へ)...ええ、これら2つは機能的にまったく同じです!どちらも関数を呼び出し、両方とも仮想関数を同様に適切に処理します。
いいえ、ラインはスライスされません。これは、ポインターによってポイントされたオブジェクトに参照を直接バインドしているだけです。
一方をもう一方よりも使用したい理由に関するいくつかの質問:
自分で違いを見つけようとする代わりに、知りたい場合はそれらに委任します。
参照は定数ポインタです。つまり、参照を変更して他のオブジェクトを参照することはできません。変更すると、参照オブジェクトの値が変更されます。
例:
int j = 10;
int &i = j;
int l = 20;
i = l; // Now value of j = 20
int *k = &j;
k = &l; // Value of j is still 10
私は長い間C ++を使っていないので、あなたの質問に本当に答えようとはしません(ごめんなさい)。ただし、Eric Lippertは優れた記事を投稿しました指し示すポインタ/参照について。
はい、機能的には同じです。参照では、使用する前にオブジェクトに設定する必要があるため、nullポインターや無効なメモリへのポインターを処理する必要はありません。
意味の違いを確認することも重要です:
- オブジェクトを実際に正常に渡す場合は参照を使用しますが、非常に大きいため、コピーを作成するよりもオブジェクトに参照を渡す方が理にかなっています(オブジェクトを変更していない場合)。
- オブジェクトではなくメモリアドレスを処理する場合は、ポインターを使用します。
スライスについて下部に隠されている2番目の質問に誰かが答えたかどうかわからない...いいえ、スライスは発生しません。
スライスとは、派生オブジェクトが基本クラスオブジェクトに割り当てられた(コピーされた)場合です。派生クラスの特殊化は「スライス」されます。オフ。 オブジェクトはコピーされると言ったことに注意してください。コピー/割り当てされるポインタについてではなく、オブジェクト自体についてです。
あなたの例では、それは起きていません。参照の初期化で右辺値として使用されているBarオブジェクトへのポインターの参照を解除するだけです(その結果、Barオブジェクトになります)。用語が正しいかどうかわからない...
他の誰もが言及したように、実装では参照とポインタはほぼ同じです。いくつかの小さな警告があります:
-
参照にNULLを割り当てることはできません (shooshはこれについて言及しました):それは ないので重要 " undefined"または「無効」参照 値。
-
一時的な 定数参照としての変数、 しかし、ポインタを渡すことは違法です 一時的に。
たとえば、これで問題ありません:
class Thingy; // assume a constructor Thingy(int,int)
void foo(const Thingy &a)
{
a.DoSomething();
}
void bar( )
{
foo( Thingy(1,2) );
}
しかし、ほとんどのコンパイラは文句を言うでしょう
void foo2( Thingy * a);
void bar2()
{
foo( &Thingy(1,2) );
}
- ポインターを取得するために変数のアドレスを取得すると、コンパイラーはそれをメモリーに保存します。ローカル変数への参照を割り当てると、同義語が作成されます。場合によっては、これによりコンパイラがレジスタにデータを保持し、を避けることができます。 load-hit-store 。ただし、これはローカル変数にのみ適用されます。参照として何かがパラメーターとして渡されると、それをスタックに保存することは避けられません。
 
void foo()
{
int a = 5;
// this may be slightly more efficient
int &b = a;
printf( "%d", ++b );
// than this
int *c = &a;
printf( "%d", ++(*c) );
}
-
同様に、 __restrictキーワードは参照に適用できません。ポインタのみ。
-
参照を使用してポインター演算を行うことはできません。そのため、配列へのポインターがある場合、配列の次の要素はp + 1を介して取得できますが、参照はその全人生。
これらの関数は明らかに「同じ」ではありませんが、仮想的な動作に関しては同様に動作します。スライスに関しては、参照またはポインターではなく、値を扱う場合にのみ発生します。