2012-01-13 6 views
3

私はこの質問に多くの記事を読みましたが、その参照はエイリアスであり、メモリを消費しません。コンパイラは参照をポインティング変数のアドレスに置き換えます。参照はC++でメモリを占有しますか?

以下の例ではどのようなことが起こるか説明できます。コンパイラのリファレンスriとの関係

int main() 
{ 
    int *pi = new int(50); 
    int &ri = *pi; 
    ri = 30; 
    cout << "val = " << ri << " , " << *pi << endl; 
} 

それは私に出力できます:

val = 30 , 30 
+0

いいえ参照はメモリを消費せず、変数や参照に加えられた変更はお互いに反映されます。それだけであなたが知る必要があります。コンパイラが処理するものはすべて、あなたは必要ありません心配して。 –

+1

参考文献はポインタの構文が少し違うと考えるのが一番です。参照のC++仕様は、技術的にはポインタではないが、コンパイラがそれらをポインタ以外のものとして扱い、依然として効率的であるとは考えにくいものである。 _Nullの処理はわずかに異なりますが、論理的にのみ、コンパイラは何もしない可能性があります_ –

答えて

2

コンパイラとして実際のオブジェクトと参照を置き換える可能性があります。これは、コンパイラが行う可能性があります一つのことである

int main() 
{ 
    int *pi = new int(50); 
    //int &ri = *pi; //compiler might remove this 

    *pi = 30; //then it replaces ri with *pi 

    cout << "val = " << *pi << " , " << *pi << endl; //here as well 
} 

を。

+0

関数の参照渡しはどうなりますか?例えばswap(int&a、int&b)はswap(i、j)とswap(x、y)のように呼び出します。 i、j、x、yはすべて整数であるとします。 –

+0

これは私が見ることができる最高の説明です。 int&ri = * pi; int * ri = piと等価です。アスタリスクを必要とせずに変数に直接アクセスすることができます。参照はnullになり得ることに注意してください(つまり、&ri == NULL)が真である場合) –

+7

@AlexisWilke:いいえ、それはnull(pedantically)にすることはできません。そのような参照を生成するには、**未定義の動作**を呼び出すヌルポインタを逆参照する必要があります。そして、その時点で、あなたのプログラムは、もはやC++標準に従わないので、C++プログラムではなくなります。 –

3
int *pi = new int(50); 

     +----+ 
pi --> | 50 | 
     +----+ 


int &ri = *pi; 

     +----+ 
pi --> | 50 | ri = 50, same as *pi, which is 50 
     +----+ 

ri = 30;  now the contents of what pi points to i.e. *pi is replaced with 30 

     +----+ 
pi --> | 30 | 
     +----+ 
0

riは、新しいメモリアドレスに割り当てることができないポインタのように機能するスタック変数です。それは主に意味論的な砂糖ですが、ポインタではできない参照では何もできません。より安全に行うことができます。この関数が終了すると、riによって利用されるスペースはスタックからクリーンアップされます。

1
int *pi = new int(50); 

あなたはintオブジェクト50を割り当てます。

int &ri = *pi; 

このintオブジェクトにエイリアスriを設定し、riをこのオブジェクトに、piをオブジェクトのアドレスに設定します。

ri = 30; 

intオブジェクトに30を再割り当てします。 riがintオブジェクトであることを忘れないでください。

cout << "val = " << ri << " , " << *pi << endl; 

riと* piは同じオブジェクトです。 オブジェクトは多くのエイリアスを持つことができ、これらのエイリアスのいずれかを使用するとオブジェクトを操作できます。

ここでは削除されます。

1

参照はエイリアスとして定義されています。標準の実装方法はあまり変わらないが、標準の表現方法は明記されていない。本質的に:一般的なケースで

  • 、参照は、ボンネットの下に、(ポインタのような)オブジェクトのアドレスである
  • 可能な場合、コンパイラは、間接
を除去するために努める

あなたのプログラムで始まる、私たちはそれを変換する方法を見てみましょう:

int main() 
{ 
    int *pi = new int(50); 
    int &ri = *pi; 
    ri = 30; 
    std::cout << "val = " << ri << " , " << *pi << std::endl; 
} 

我々はできますそれがバインドされているオブジェクトは、コンパイラによって知られているので、riを排除:

int main() 
{ 
    int *pi = new int(50); 
    *pi = 30; 
    std::cout << "val = " << *pi << " , " << *pi << std::endl; 
} 

その最終値は、コンパイラによって知られているので、我々は*piを排除することができます

int main() { 
    new int(50); // stupid possible side effect usually forbid to optimize this out 
    std::cout << "val = " << 30 << " , " << 30 << std::endl; 
} 

私はあなたにそれを注意しますたとえば、new呼び出しは完全に無用です。動的に割り当てられていないオブジェクトも参照できます。

int main() { 
    int i = 50; 
    int& ri = i; 
    ri = 30; 
    std::cout << "val = " << ri << " < " << i << std::endl; 
} 

も有効で、メモリリークはありませんでした。


バック表現の間我々の違いを取得:

void swap(Foo& left, Foo& right); 

典型的に実装されている:この場合

void swap(Foo* left, Foo* right); 

、参照は、(一部)を服用してしまう空間(ASポインタと同じくらい)。と一方

class Object { 
public: 
    Object(): foo(f), f() {} 

    Foo const& foo; 

    void set(Foo const& value); 

private: 
    Foo f; 
}; 

コンパイラは、一般的にfooランタイム表現を与えることはありませます。それがconstの参照であるという事実は、fで呼び出される可能なメソッドを変更しないメソッド(意味的な違い)に制限するために使用されますが、実行時には直接fが渡されます。

0

参照変数は、以下に示すように、C++プログラムを作成 ....以下に示すようにこれをテストするための最良の方法は、C++プログラムのアセンブリを使用して、スタック上のメモリを取り、それ

のアセンブリを生成します
#include<iostream> 
using namespace std; 

int main(){ 
int i = 100; 
int j = 200; 
int &x1 = i; 
int &x2 = i; 
int &x3 = i; 
int &x4 = i; 
int &x5 = i; 
int &x6 = i; 
int &x7 = i; 

cout << "reference value" << x1 << endl; 
return 0; 

}

このプログラムのアセンブリは、スタックポインタは「基準がメモリを取得する手段」は36バイト件まで下降することを示しています。命令(ESP、%を$ 64 SUBL)上記

main: 
.LFB966: 
.cfi_startproc 
    pushl %ebp 
    .cfi_def_cfa_offset 8 
    .cfi_offset 5, -8 
    movl %esp, %ebp 
    .cfi_def_cfa_register 5 
    pushl %ebx 
    andl $-16, %esp 
    subl $64, %esp 
    movl $100, 28(%esp) 

は私のためのスペースを割り当てるため、スタックポインタの移動で、jとスタック上(X7へX1)7つの参照変数。

命令以上
main: 
.LFB966: 
    .cfi_startproc 
    pushl %ebp 
    .cfi_def_cfa_offset 8 
    .cfi_offset 5, -8 
    movl %esp, %ebp 
    .cfi_def_cfa_register 5 
    pushl %ebx 
    andl $-16, %esp 
    subl $32, %esp 
    movl $100, 20(%esp) 

"$ 32 SUBL、%espを"

あなたは12バイトのスタックポインタの動きを示すことの

#include<iostream> 
using namespace std; 

int main(){ 
int i = 100; 
int j = 200; 
int &x1 = i; 
cout << "ref changed" << x1 << endl; 
return 0; 
} 

以下のようにcppのプログラム上のアセンブリを変更した場合..スタックされるポインタスタック上のi、j、x1参照変数のためのスペースを割り当てる動き

私は上のすべての事をクリアすると信じています。間違っていると私を訂正してください:)

関連する問題