C++におけるポインタ変数と参照変数の違いは何ですか?

リファレンスは、コードを読みやすく書きやすくするための構文上の糖であることは知っています。

しかし、どのような違いがあるのでしょうか?


以下の回答とリンクからまとめてみました。

1.ポインタは何度でも再割り当てが可能ですが、参照はバインド後は再割り当てができません。 2.ポインタはどこも指さない(NULL)が、参照は常にオブジェクトを参照する。 3.ポインタのようにリファレンスのアドレスを取ることはできません'。 4.4. 参照演算はできません(ただし、&obj + 5のように、参照が指すオブジェクトのアドレスを受け取り、それに対してポインタ演算を行うことはできます)。

誤解を解くために。

C++標準では,コンパイラがどのように参照を実装するかを規定しないように細心の注意を払っています。 しかし、すべてのC++コンパイラは、参照をポインタとして実装しています。 しかし、すべてのC++コンパイラは、参照をポインタとして実装しています。つまり、次のような宣言が必要になります。

int &ri = i;

完全に最適化されていなければ、*ポインタと同じ量のストレージを確保します。 ポインタとして同量のストレージを確保し、iのアドレスを i "のアドレスをそのストレージに格納します。

***つまり、ポインタとリファレンスは同じ量のメモリを使用することになります。

一般的には

  • 関数のパラメータや戻り値の型には参照を使用して、便利で自己記録的なインターフェイスを提供する。
  • アルゴリズムやデータ構造の実装にはポインタを使用します。

興味深い読み物です。

  • 私がいつも愛用しているC++ FAQ lite
  • リファレンスとポインターの比較]2
  • 参考文献の紹介]3を参照してください。
  • リファレンスとconst]4を参照してください。
  1. ポインタは再割り当てが可能です。

    int x = 5;
    int y = 6;
    int *p;
    p = &x;
    p = &y;
    *p = 10;
    assert(x == 5);
    assert(y == 10);

    参照は初期化時に割り当てることができないため、割り当てる必要があります。

    int x = 5;
    int y = 6;
    int &r = x;
  2. ポインタは独自のメモリアドレスとスタック上のサイズ(x86では4バイト)を持っていますが、参照は(元の変数と)同じメモリアドレスを共有しますが、スタック上にもスペースを取ります。 参照は元の変数と同じアドレスを持つので、参照は同じ変数の別の名前と考えてよいでしょう。 注意: ポインタが指すものは、スタックやヒープ上にあってもかまいません。 参照の場合も同様です。この文章で私が主張しているのは、ポインターがスタックを指していなければならないということではありません。 ポインタは、メモリアドレスを保持する変数に過ぎません。 この変数はスタック上にあります。 参照はスタック上に独自の空間を持ち、アドレスは参照する変数と同じであるからです。 詳しくは[スタック vs ヒープ][1]をご覧ください。 これは、コンパイラが教えてくれない参照の実アドレスがあることを意味します。

    int x = 0;
    int &r = x;
    int *p = &x;
    int *p2 = &r;
    assert(p == p2);

3.ポインターへのポインターは、追加のインダイレクト・レベルを提供します。 一方、参照は1つのレベルのインダイレクトしか提供しません。

    int x = 0;
    int y = 0;
    int *p = &x;
    int *q = &y;
    int **pp = &p;
    pp = &q;//*pp = q
    **pp = 4;
    assert(y == 4);
    assert(x == 0);

4.ポインタは直接 nullptr を代入できますが、リファレンスは代入できません。努力すれば、そしてその方法を知っていれば、参照のアドレスを nullptr にすることができます。 同様に,十分な努力をすれば,ポインタへの参照を持つことができ,その参照には nullptr を含めることができます。

    int *p = nullptr;
    int &r = nullptr; 
解説 (43)

構文上の問題を除けば,参照とはconst`のポインタです(const`へのポインタではありません).参照変数を宣言するときに,何を参照しているかを設定しなければならず,後で変更することはできません。

Update: 今、もう少し考えてみると、重要な違いがあります。

const ポインタのターゲットは、そのアドレスを取って const キャストを使うことで置き換えることができます。

リファレンスのターゲットはUB以外の方法では置き換えられません。

これにより、コンパイラは参照に対してより多くの最適化を行えるようになります。

解説 (5)

参照は決して NULL にはなりません。

解説 (10)