1

在下面的代碼中,演示了兩個函數。 f1()返回函數作用域中初始化局部變量的引用,f2()返回函數作用域中初始化局部變量的值。返回本地變量的參考

由於本地初始化變量,f2()預計可以正常工作。值從堆棧傳遞到主。

由於本地變量的引用在函數作用域外無用,所以f1()不會工作。但是,兩種功能的輸出似乎都可以。

這裏是測試代碼;

#include <iostream> 
using namespace std; 

// function declarations 
int& f1(); 
int f2(); 

int main() 
{ 
    cout << "f1: " << f1() << endl; // should not work! 
    cout << "f2: " << f2() << endl; // should work 

    return 0; 
} 

int& f1()  // returns reference 
{ 
    int i = 10; // local variable 

    return i; // returns reference 
} 

int f2()  // returns value 
{ 
    int i = 5; // local variable 

    return i; // returns value 
} 

輸出如下;

f1: 10 
f2: 5 

爲什麼f1()工作正常,即使f1()返回局部變量的引用?

+5

因爲你喚起了未定義的行爲,這樣做的天空是極限。 – 101010

+0

因爲你一直非常幸運...... – Chiel

+0

你預計會發生什麼? – emlai

回答

5

歡迎來到未定義的行爲

這就是你正在做的。你訪問一個超出範圍的變量。但是,這可能是因爲系統沒有寫入已經存在的值,這解釋了行爲。

這就是爲什麼在真實代碼中找到這樣的邏輯錯誤很難。因爲你可能(非)幸運,並且變量具有正確的值(在該特定執行中)。

因此,f1()的返回值是對超出範圍的東西的引用,而f2()的返回值是該函數的局部變量的副本,這是正確的。


然而,血統編譯器應該提醒你注意這一點,與這樣的警告:

警告:引用局部變量「我」返回[-Wreturn-本地地址]

請在您的編譯器中啓用您的警告標誌。 :)

7

訪問超出範圍的局部變量是未定義的行爲。未定義的行爲意味着程序可能工作,它可能會出現段錯誤,它可能會打印垃圾值和所有內容。

低級原因因爲這是局部變量位於堆棧上。堆棧屬於進程的可寫地址空間(至少在大多數情況下,如果不是全部的話,就像你的那樣)。該程序可能會寫入它就像它想。 然而,,寫入堆棧是C++不支持的東西。 C++只定義局部變量,而不是調用幀或返回地址。它駐留在更高層次的抽象中。支持直接寫入堆棧的唯一語言是Assembly。


其理由沒有被以任何方式的C++標準指定。