2012-03-06 20 views
5

例如這個函數f是這樣定義的:爲什麼你可以通過引用返回一個局部變量而不是臨時變量的函數? C++

int f(int x){return x;} 

你知道你不能分配給該臨時INT參考:

int& rf=f(2);// this will give an error 

但如果我重新定義了我的函數f這樣:

int& f(int x){return x;} 
f(2);// so now f(2) is a reference of x, which has been destroyed 

所以我的問題是:如何編譯器不讓你創建一個temp的引用在該陳述後將被銷燬的文件(在第一種情況下)。另一方面它可以讓你創建一個參考f(2)到x,而編譯器知道這個將在return之後被銷燬。

+1

這是UB(好吧,無論如何都要訪問參考),任何理智的編譯器都會提醒你。 – 2012-03-06 15:35:55

回答

7

返回到本地一提的是東西,可以是難以或不可能編譯器來檢測。例如:

int & f() 
{ 
    int x; 
    extern int & g(int & x); 

    // Does this return a reference to "x"? 
    // The compiler has no way to tell. 
    return g(x); 
} 

即使沒有調用外部函數,它仍然是難以分析複雜的程序流程,告訴返回的引用是否是到本地;而不是試圖定義什麼是「足夠簡單」來診斷,標準不需要診斷 - 它只是表明它給出了未定義的行爲。一個好的編譯器應該給出一個警告,至少在簡單的情況下。

將臨時綁定到非const引用是編譯器可以輕鬆檢測的事情,因此標準確實需要診斷。

1

因爲按照標準的規定,從函數返回一個臨時變量的引用是未定義的行爲。

什麼問題實際上是函數的定義:

int& f(int x) 
{ 
    return x; 
} 
0

這不是一個好主意,通過引用,除非你確信你返回參考仍將在一些有效的是指向返回。

否則,未定義的行爲是預期的。

自變量是本地的,你可以肯定的是德引用無效

+2

由於變量是本地變量,因此可以確定它是無效的。 – 2012-03-06 15:42:57

1

您可以將臨時右值綁定到const引用以延長其生命週期。

const int& rf=f(2); 
0

的問題是,在語義上有一個堆棧上堆等變量的變量沒有什麼區別,或者 - 所以語言沒有選擇,只能允許這樣做,即使它是不確定的行爲。 在第一個例子中,你會遇到一個簡單的編譯錯誤,因爲你試圖綁定一個臨時變量的引用,這個變量可以被語言禁止。

+0

是的,我明白,但爲什麼它適用於第二個例子?以及爲什麼你提到堆,我沒有說關於堆的任何信息 – AlexDan 2012-03-06 15:53:12

+0

@AbdessamadBond有答案爲什麼你的第二個例子不起作用..並且我提到了堆,因爲返回對堆上變量的引用是好的(即使它可能是壞風格)。在語義上,堆中的變量和堆棧中的變量之間沒有區別,而變量和臨時值之間存在差異。 – cooky451 2012-03-06 16:34:57

1

要拒絕您的第一個代碼片段,編譯器會應用您不能將臨時綁定到非const引用的簡單規則。

要拒絕第二個,編譯器可能會應用一條規則,即通過引用返回的函數的return語句不能是自動變量(包括按值函數參數)的名稱。這在我看來也是一個相當簡單的規則。

我不知道爲什麼標準沒有說明這樣做是不合格的。我想不出任何有效的用法,但也許在第一個標準的時候,它會給某些實施或其他方面造成過大的負擔。或者也許人們覺得這只是一個解決方案,不值得打擾(還有很多其他方法可以創建一個懸掛參考,這隻會阻止其中一個)。

標準一般不會停止創建綁定到臨時的非const引用的原因是有些情況下可以。例如:

struct Foo { 
    static void set(Foo &f) { f.val = 0; } 
    int val; 
    int bar() { 
     set(*this); 
     return val; 
    } 
}; 

std::cout << Foo().bar() << "\n"; 

這裏Foo()是暫時的,並且線set(*this)其結合非const引用(但不直接,它使用一個左值表達式*this引用到一個臨時一些倍而不是其它) 。這裏沒有問題,暫時只是參考。因此,對語言來說,不必要的限制就是防止任何臨時的限制被綁定到任何非const引用。

相關問題