2011-09-21 63 views
2

爲什麼此代碼可以在Code :: block中成功運行。美洲開發銀行剛剛報道返回對本地變量的引用

警告: 「參照局部變量‘TMP’返回」,

但輸出中的結果 「Hello World」 的成功。

#include <iostream> 
#include<string> 
using namespace std; 

const string &getString(const string &s) 
{ 
    string tmp = s; 
    return tmp; 
} 

int main() 
{ 
    string a; 
    cout<<getString("hello world")<<endl; 
    return 0; 
} 
+1

[返回局部或臨時變量的地址]的可能重複(http://stackoverflow.com/questions/2744264/returning-the-address-of-local-or-temporary-variable) – iammilind

回答

1

您正在導致未定義的行爲。該標準並沒有說明在這種情況下會發生什麼,然而你的編譯器檢測到它。

2

在離開函數時,所有局部變量都被銷燬。通過返回對tmp的引用,您將返回對即將不復存在的對象的引用(即從技術上說,內存區域的內容不再有意義的地址)。

訪問這樣的懸掛引用調用所謂的'未定義行爲' - 可悲的是,'照常工作'是一種'未定義的行爲'。這裏可能發生的情況是std::string爲小字符串保留了一個小的靜態緩衝區(與大字符串相反,爲此它從堆中獲取內存),並且在離開getString時,此字符串佔用的堆棧空間未被清零,因此它似乎仍然上班。

如果您嘗試調試構建,或調用其中一個函數(這將有效覆蓋堆棧空間),它將不再工作。

+0

公寓添加**不要這樣做**並且不要依賴編譯器會在某些情況下返回給您有效的字符串,爲此您可能會發現它可以正常工作,但不能保證它能在下次使用。 –

1

tmp在您從getString返回的那一刻消失。使用返回的引用是未定義的行爲,所以任何事情都可能發生。

要修復您的代碼,返回值的字符串:

string getString(const string &s) 
{ 
... 
0

你確定嗎?它應該segfault(它將在大多數平臺上與gcc)。該代碼確實包含錯誤,如果您獲得「幸運」並且它有效,那麼您正在刷下地毯下的一個令人討厭的錯誤。

您的字符串是通過引用返回的,也就是說,不是在返回的上下文中創建一個有效的新字符串,而是返回一個陳舊的,被銷燬的對象的指針,這是不好的。 const string getString...將作爲函數返回類型的聲明。

0

臨時對象被釋放,但是它的內容仍然在堆棧中,直到重寫它爲止。嘗試調用調用你的函數,並打印出返回的對象之間的一些功能:

const string& garbage = getString("Hello World!"); 
callSomeFunctionThatUsesALotOfStackMemory(); 
cout<< garbage << endl; 
0

C++標準告訴一個臨時對象綁定到一個常量引用的臨時的壽命延長到基準本身的壽命。因此,代碼應該適用於任何符合標準的編譯器,但在我看來,這種做法本身並不是很好。

如果你在你的例子中使用了一個當前未使用的字符串作爲字符串a = getString(「Hello World!」),你只需製作一個副本,如果是const字符串& a = getString(「Hello World! 「)我敢打賭,你永遠不應該有你的臨時垃圾。

0

正如你所看到的,通過調用goodByeString()稍微修改下面的示例代碼。像其他答案一樣,已經指出,名爲tmp的getString中的變量是本地的。只要函數返回,變量就會超出範圍。因爲它是堆棧分配的,所以當函數返回時內存仍然有效,但是一旦堆棧再次增長,tmp駐留的這部分內存就會被別的東西重寫。然後,對a的引用包含垃圾。

但是,如果您決定輸出b,因爲它不是通過引用返回,則內容仍然有效。

#include <iostream> 
#include<string> 
using namespace std; 

const string &getString(const string &s) 
{ 
    string tmp = s; 
    return tmp; 
} 

string goodByeString(const string &s) 
{ 
    string tmp = "lala"; 
    tmp += s; 
    return tmp; 
} 

int main() 
{ 
    const string &a = getString("Hello World!\n"); 
    string b = goodByeString("ciao\n"); 
    cout << a << endl; 
    return 0; 
}