[英]Returning reference to a local variable
為什么這段代碼可以在Code::block 中成功運行。 IDB 剛剛報告
警告:“返回對局部變量‘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;
}
離開函數后,所有局部變量均被銷毀。 通過返回對tmp
的引用,您將返回對一個對象的引用,該對象不久將不復存在(即,從技術上講,其內容不再有意義的內存區域的地址)。
訪問這種懸空的引用會調用所謂的“未定義的行為”,而可悲的是,“照常工作”是一種“未定義的行為”。 這里可能發生的情況是std::string
為小字符串(與大字符串相反,它從堆中獲取內存)保留了一個小的靜態緩沖區,並且在離開getString
,此字符串占用的堆棧空間未清零,因此它似乎仍然有效。
如果您嘗試調試構建,或在兩者之間調用另一個函數(這將有效覆蓋堆棧空間),則它將不再起作用。
您正在引起不確定的行為。 該標准無法說明在這種情況下會發生什么,但是編譯器已檢測到它。
從getString
返回的那一刻, tmp
消失了。 使用返回的引用是未定義的行為,因此任何事情都可能發生。
要修復您的代碼,請按值返回字符串:
string getString(const string &s)
{
...
也許此鏈接會為您提供幫助。
你確定嗎? 它應該是段錯誤的(在大多數平台上,它將與gcc一起使用)。 該代碼確實包含一個錯誤,如果您“幸運”並且可以正常工作,那么您就在地毯下刷了一個討厭的錯誤。
您的字符串是通過引用返回的,也就是說,不是生成一個在您要返回的上下文中有效的新字符串,而是返回了一個指向過期,已破壞的對象的指針,這很糟糕。 const string getString...
將用作函數返回類型的聲明。
臨時對象被釋放,但是它的內容仍然存在於堆棧中,直到有人重寫它為止。 嘗試在調用函數和輸出返回的對象之間調用一些函數:
const string& garbage = getString("Hello World!");
callSomeFunctionThatUsesALotOfStackMemory();
cout<< garbage << endl;
C ++標准告訴我們,將臨時對象綁定到const引用可以將臨時對象的生存期延長到引用本身的生存期。 因此,該代碼應可在任何符合標准的編譯器上工作,但在我看來,這種做法本身並不是很好。
如果您確實使用示例中當前未使用的字符串作為字符串a = getString(“ Hello World!”),則只需復制一個副本,如果使用const string&a = getString(“ Hello World!”),我敢打賭您永遠不應該浪費您的臨時工。
如您所見,通過調用goodByeString()可以稍微修改以下示例代碼。 就像其他答案一樣,getString中名為tmp的變量是本地變量。 函數返回后,變量將超出范圍。 由於是堆棧分配的,因此函數返回時,內存仍然有效,但是一旦堆棧再次增長,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;
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.