2013-11-02 183 views
1

你能告訴我爲什麼在不同編譯器中類的引用成員的輸出是不同的?
類參考成員列表初始化

class B 
    { 
    int& aRef; 
    public: 
    B(int c):aRef(c){} 

    void Print() 
    { 
     cout<<aRef<<endl; 
    } 
    }; 

    void f(int s) 
    { 
    int& lcRef=s; 
    cout<<lcRef<<endl; 
    } 

int main() 
{ 
    int x=100; 
    B s(x); 
    s.Print(); //ms c++ output : 3323244, gcc output :100 
    f(x); //ms c++ output : 100, gcc output:100 
    return 0; 
} 


和功能f(int s)秒問題參數的行爲相同的邏輯,B類的初始化的構造器?

+2

你保存參考到一個臨時(了'INT c'parameter到'B'構造函數)。一旦構造函數完成,它不再處於範圍內,被銷燬,然後你有一個懸而未決的參考。之後訪問它是**未定義的行爲**。 – WhozCraig

回答

5
B(int c):aRef(c){} 

這將引用綁定到構造函數參數c。由於它是按值傳遞的,所以當構造函數返回時它會被銷燬,從而導致引用懸而未決。在構造函數返回後訪問它給出未定義的行爲;在這種情況下,它會嘗試訪問一堆可能可以訪問或可能不可訪問的釋放堆棧內存,並且可能包含或不包含舊值。

你想通過引用傳遞,結合呼叫者的變量:

B(int& c) : aRef(c) {} 
+0

gotcha因此,如果將f()的返回類型更改爲int&並且僅僅在不使用cout的情況下返回lcRef,那麼它的未定義行爲將與構造函數相同? –

+0

woow awsome現在我可以理解爲什麼通過引用存在?該死的是一種編程語言..謝謝 –

+0

@DonCarleone:是的,如果有人使用引用,返回一個局部變量的引用也會給出未定義的行爲。如果啓用警告,編譯器通常可以警告有關這些問題。 –

4

f功能是否正確,如預期,但這裏的工作原理:

B(int c):aRef(c){} 

你基本上分配給int& aRef地址到本地自動分配的變量(c)。現在,引用比指針更安全,但是分配一個自動分配的變量超出了範圍,這是使它們失效的少數情況之一。

在GCC上輸出正確的事實並不意味着任何事情,因爲該變量在構造函數中不再有效。

+0

+1。我們甚至無法準確地說GCC的輸出是「正確的」,因爲這個術語需要明確的結論,這是完全不存在未定義(即缺少任何定義)行爲本質的條件。 – WhozCraig

2

所不同的是,f中,您正在參考參數。通過參考打印內容時,此參數仍然有效。對於B的構造函數,你是存儲引用,並且當構造函數完成時,引用的對象超出範圍,因此引用變成懸掛引用,並使用它成爲無效。海灣合作委員會的輸出只是一個巧合,但不能保證。