c++ 臨時變數問題?

#include &
#include &
using namespace std;

const string Func()
{
return "123";
}

int main()
{
string s = Func();

cout &<&< s &<&< endl; return 0; }

const 引用不是會提升臨時變數的生命期嗎? 為什麼返回函數內的臨時變數會報錯了? 我對const引用的理解哪裡錯了嗎?

#include &
#include &
using namespace std;

const string Func(const string s)
{
return s;
}

int main()
{
string s = Func("123");

cout &<&< s &<&< endl; return 0; }

但是這段代碼就可以了。 Func函數參數綁定到一個臨時變數,然後返回這個臨時變數的const引用,就沒有問題?

why?


const 引用不是會提升臨時變數的生命期嗎?」說的是這種情況:

string bitch()
{
return "shit";
}

int main()
{
const string fuck = bitch();
return 0;
}

而不是題主你自以為的那一種


你第一個代碼其實是這樣

const string Func()
{
string tmp = "123";
return tmp;
//tmp這裡被析構了
}
const引用提升生命期,是將臨時變數的「在full expression結束銷毀」提升為
「在const引用生命結束銷毀」,而不是你這個例子的情況,
正確的適用情況 @vczh 舉了


首先你要明白引用不是一個對象,而是綁定對象的別名。

在你第一個例子中的

const string Func()
{
return "123";
}

可以理解為

const string Func()
{
const string temp = "123";
return temp;
}

在func()函數結束時,臨時對象temp已經銷毀了,綁定temp的引用就不能用了。

而第二個例子

const string Func(const string s)
{
return s;
}

int main()
{
string s = Func("123");
cout &<&< s &<&< endl; return 0; }

可以理解為

int main()
{
const string temp = "123";
string s = Func(temp);
cout &<&< s &<&< endl; return 0; }

臨時對象temp的作用域是整個main()函數。

《C++ Primer 第五版》中第二章中,關於引用和const的概念會有詳細介紹。


引用不管理生命周期

誰告訴你可以返回局部自動變數的引用了

返回引用一般是返回類成員的引用 全局變數的引用 堆上內容的引用

而且你這裡多此一舉 返回左值引用後又通過拷貝構造構造一個新的string

正確做法:

class Foo
{
public:
auto getName() const
{
return name;
}

private:
std::string name;
};

Foo f;
auto name = f.getName();

@vczh

解釋一下輪子哥的代碼:

本質也不是引用管理了生命周期

只不過調用返回值類型的函數時本身就創建了一個匿名對象

(c++11中所有作為值類型返回的類型必須有可訪問的移動構造函數,因為從返回值到匿名對象需要調用移動構造函數)

引用只是將其具名化

匿名對象沒被具名化時的生命周期是編譯器決定的

因為沒具名化之前 代碼中只可能去訪問到一次匿名對象

所以一般編譯器會選擇立刻釋放(或者索性不創建匿名對象 這就是RVO)

不過其實立刻釋放還是等到函數結束一起釋放都可以

所以匿名對象也可以一直存在到函數結束 只是你再也看不到它而已

既然你看不到了 編譯器就有權利"偷偷摸摸"把它優化了

具名化之後 就等於告訴編譯器 我給這個匿名對象命名了

編譯器就不能偷偷摸摸的因為我看不到它了就把它"優化"了

不過引用也不會管理這個匿名對象的生命周期

舉個例子

如果一個編譯器 決定在函數結束時才釋放所有自動變數 包括匿名對象

那麼你給一個匿名對象具名化了

然後把這個引用放到一個block里

這個block結束後

這個雖然引用就看不到了

不過匿名對象並不會釋放

仍舊只會在函數末尾釋放

所以引用並不管理生命周期(無論是具名對象還是匿名對象的生命周期都不歸引用管理)

對匿名對象的引用只是標示了其的可見性

匿名對象的到底什麼時候死還是看編譯器


返回引用是常見的C++誤用. 首先const引用並沒有改變臨時變數有效期的作用, 所以返回後引用對象被銷毀導致報錯. 其次即使對於非臨時變數, 返回引用的用法也不好界定, 要麼什麼作用也沒有, 比如你的第二段代碼, 要麼導致變數所屬權模糊, 引發維護性問題. 所以基本上, 除非你十分確定自己想要這種寫法, 比如說實現move語義, 否則盡量避免返回引用.

看大家幾小時這麼多回復, 不禁感慨輪子哥的魅力, 咔咔.

說正題, 臨時變數也是C++說不清道不明的東西, 我大致理解為強行兼容C和OOP所帶來的混亂. 其中有個略神髓的xvalue概念, 再牽扯到右值引用, 真是凌亂. 其實最後這些東西多數都是用來做庫優化的.


推薦閱讀:

為什麼 Python 現在(2015年)越來越火了?
想提高編程能力,請大家評價這種學習方法是否可取?
考慮到未來人工智慧的發展,應該學習C++/C語言還是Python語言?
大學理科生零基礎自學計算機和編程有哪些書籍和方法比較好?
對於一個程序員來說,寫代碼用台式機好還是筆記本好?

TAG:編程語言 | 編程 | C | CC |