同樣的函數引用里為什麼使用string引用時會清空數據?
在把string類型改成int基本類型或者直接使用前面的string a之後就沒有這種現象,為什麼?代碼如下
using namespace std;int main(){ const string print(const string ); float b = 11.17; string a = "cba"; const string d= print("abc"); cout &<&< d &<&< "==&>" &<&< d &<&< " "; cin &>&> b;return b;
}const string print(const string l){ cout &<&< l&<&<"==&>" &<&< l &<&<" "; return l;}
你放截屏的意思是要我手敲一遍代碼去復現?
感覺沒人答到點子上啊。。。
你傳入的是"abc"
形參類型是const string相當於在函數體內部使用"abc"構造了一個string的臨時對象,並把其綁定在了"L"上
之後函數運行完這個string局部臨時對象就析構了所以你這個問題就是「返回了局部對象的引用」
如果不在函數內部建立臨時對象,而是在外部建立就沒有任何問題,如下:const string d= print("abc");
應該是因為這個傳進去的是個臨時變數,而參數和返回值都是引用傳遞。字元串裡面用完了(超出作用域)就被釋放了,所以返回時就返回了一個空的。返回值去掉引用,可能就能得到"abc"了。
補張圖:
改成print(a)就可以正常顯示,因為a已經分配好了,main函數返回才析構。而「abc」是在參數中的,調用的時候先生成一個string 臨時變數,然後用構造函數初始化,string有個參數是const char *的構造函數。調用完成之後,就析構這個臨時變數了,而d引用了一個已經析構的臨時變數。至於int類型,實際是一樣的,只不過int析構的時候不會把int值改成0,而string析構的時候把字元串設置成空了。c++引用坑居多,不用引用是更好的選擇。
你引用棧上的東西,返回即析構,出什麼結果都有可能。
@陳碩 這種問題你都回,影響timeline啊。匿了。能懂就懂,不懂也沒關係.這個已經超出了C++語言的範疇.知道有這麼回事情就行了.
-----------嗯...為什麼沒有人點贊?...嗯...嗯...睡覺~必須返回對象時,別妄想返回其reference~~~~~Effective cpp 條款21。不要輕易嘗試返回局部對象的引用,如有必要,請返回右值引用。
《深度探索C++對象模型》第275頁:如果一個臨時性對象被綁定於一個reference,對象將殘留,直到被初始化之reference的生命結束,或直到臨時對象的生命範疇(scope)結束——視哪一種情況先到達而定。(候捷先生的翻譯略有點生硬)
例如:const string s = "abc";會產生這樣的程序代碼:string temp;temp.string::string("abc");
const string s = temp;此時,臨時對象會殘留。對於題中的臨時對象,生成後被綁定到函數的形參(同上面的例子)。
按上述規則,函數調用完成後,可以認為是被初始化之reference的生命結束,也可以認為是臨時對象的生命範疇結束(畢竟是棧上的變數,函數調用結束會退棧,退棧之前編譯器會隱式插入string的析構函數),那麼此時臨時對象也不再殘留而被析構,從而d引用到的是析構後的string對象(l和d的地址相同)。但是,退棧並不會把之前的棧上數據清零,所以d還能訪問到棧上的string對象,看到其size成員變數。而string對象的析構函數會把size置成0,那麼通過變數d 訪問時,由於d.size為0,&<&<操作符不列印任何字元,從而觀察到「清空數據」的假象。事實上,析構後的string對象的狀態是未定義的,上述情形只是在MSVC下的實現而已,用於解釋題中看到的現象。正如《Effective C++》條款21所言:必須返回對象時,別妄想返回其reference。你引用其他函數的局部變數還想怎樣
返回局部變數,代碼本身就有問題,string類型是一個類,當它生命周期結束時會析構而引起內容消失,int類型看起來正確,但數值是不安全的,可以被別的程序隨意修改
這個居然能編譯過嗎?內部引用不能穿出才對呀
啊,不對我錯了,這個是臨時對象的引用
你沒理解reference和const reference。
我還是比較好奇,你是如何把一個右值綁定到一個引用上的?msvc有特殊技巧嗎
----
修正,首先承認錯誤,看題目要看完整再回答,看完整,看完整,看完整。的確,右值不應該,程序猿也萬萬不能將其被綁定在一個左值引用上(不管他是const亦或者不是const,但是MSVC裡面竟然可以,吃驚),右值應當被一個左值先妥妥的存起來(不應該搞起來就直接用,除非是一次性的),然後就可以做任何你想做的事了。【然而這並不是題主的題目】
題主的print函數為const string print(const string l) ,當調用函數時"abc「,此時"abc"還是一個右值,然後很據函數匹配原則以及右值當左值用的原則,const string l 雖然不是最優,但是可以匹配, 好,那就愉快的當左值用了然而函數用完可是會給你愉快的析構的啊啊啊,也就是說,這個」abc「已經死了,之所以還能列印出來自己的地址,那是"abc"的殘念太深啊啊啊。總結」abc「菌經歷了傳奇的一生-&> ( = ) -&> 析構 -&>return -&> 在main中取地址
最後"abc"菌已經出問題了,建議不要繼續使用,待會兒就要燙燙燙燙了推薦閱讀: