2012-01-13 79 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

沒有提及不消耗任何存儲器和變量或引用所做的任何更改都將反映到對方,這就是你需要know.Everything否則編譯器會照顧的唯一的事情,你不需要擔心。 – 2012-01-13 06:31:52

+1

你最好只考慮引用是指針的稍微不同的語法。 C++的引用的規範是這樣的,雖然技術上沒有指針,這將是極不可能的編譯器可以把它們當作什麼,但三分球,仍然是有效的。 _NULL處理略有不同,但同樣,只有邏輯,編譯器是不可能做任何事情different_ – 2012-01-13 10:18:59

回答

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)。考慮我,j,x,y都是整數。 – 2012-01-13 06:01:19

+0

這是我能看到的最好的解釋。 int&ri = * pi;相當於int * ri = pi;它只是給你「直接」訪問變量而不需要星號。請注意,引用可以是空 – 2012-01-13 06:19:46

+7

@AlexisWilke(即,如果(RI == NULL)可以實現的。):沒有,它不能爲空(迂腐)。爲了產生這樣的引用,你需要解引用一個空指針,它調用**未定義的行爲**。在那時你的程序不再是一個C++程序,因爲它不再服從C++標準。 – 2012-01-13 07:09:32

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是這個對象和pi是對象的地址;

ri = 30; 

重新分配30給int對象;記得ri是int對象;

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

ri和* PI是相同的對象。 你只記得一個對象可能有許多別名,並且使用這些別名中的任何一個都可以操作該對象。

和where刪除。

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); 

在這種情況下,參考最終採取(部分)的空間(如很像指針)。

在另一方面有:

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字節「這意味着參考獲取存儲器」。

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) 

上述指令(subl $ 64%ESP)是堆棧指針移動到對於i分配空間,j和在堆棧上七個參考變量(x1至X7)。

如果改變上述CPP程序如下

#include<iostream> 
using namespace std; 

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

大會它示出的12個字節堆棧指針運動..

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) 

上述指令 「subl $ 32%ESP」 是堆棧指針移動堆棧上的i,j和X1的參考變量分配空間

我相信上述實際清除每一件事情,糾正我,如果我錯了.. :)