2016-02-12 65 views
6

我想知道爲什麼返回本地對象的const reference是非法的,而只要您將它分配給const reference就返回local object是合法的?返回常量引用vs臨時對象

vector<int> f_legal() { 
    vector<int> tempVec; 
    tempVec.push_back(1); 
    return tempVec; 
} 

const vector<int>& f_illegal() { 
    vector<int> tempVec; 
    tempVec.push_back(1); 
    return tempVec; 
} 

void g() { 
    const vector<int>& v1 = f_legal(); // legal 
    const vector<int>& v2 = f_illegal(); // illegal 
} 

編輯: 我的觀點是,如果分配一個const裁判返回的本地變量是合法的,那麼不應該指定一個const裁判的局部變量返回的常量裁判是合法的呢?

+2

@Ed Heal是的,它在C++中定義良好,本地const引用將延長它所綁定的臨時對象的生命週期。 –

+2

@EdHeal是的,這是合法的。標準中有一個特殊情況,只要在當前範圍內有一個const引用,就會保持本地對象的活動。 –

回答

6

即使您將它分配給常量引用,返回值也會被聲明爲按值傳遞,這意味着它將作爲臨時對象複製到外部,然後綁定到常量引用。將臨時對象綁定到const引用是好的,該對象不會被銷燬,直到超出const引用的生命週期。

另一方面,返回局部變量的引用是非法的。當函數返回時,局部變量將被銷燬,這意味着外部引用將被懸置。

編輯

我的觀點是,如果分配一個const裁判返回的本地變量是合法的,那麼不應該以一個局部變量返回的常量裁判指派一個const裁判是合法的好?

點是第一種情況下並不分配一個const裁判返回的局部變量,它分配一個常量裁判返回的臨時變量。 (這可能從本地變量複製。)


[1]副本可能根據RVO技術上被省略。

+0

你確定情況總是如此嗎?即使考慮「RVO/NRVO」? –

+0

@JamesAdkison:會有一個臨時對象,並且引用將綁定到該臨時對象。該副本可能會被忽略(如果結果可以直接在臨時構建)。 –

+0

@BenVoigt是的,那是我的觀點(即複製可能會被忽略)。 –

8

返回對局部變量的引用是非法的(未定義行爲)。期。沒有constmutable子句。

這是因爲本地函數變量具有自動存儲持續時間。在函數退出後它們被「銷燬」。如果該函數返回對這樣一個變量的引用,那麼該引用被稱爲懸而未決:它指的是不再存在的對象。

由於特殊的C++規則,第一個是合法的:初始化對prvalue的引用將該臨時對象的生命週期延長到引用的生命週期。

+0

該規則實際上與'const'無關 - 任何直接綁定到臨時對象的引用都會延長該臨時對象的生命週期。在C++ 98中,其他規則規定只有const引用可以直接綁定到臨時的,那些規則現在已經改變,這對於生命週期擴展規則具有多米諾骨牌效應。 –

+0

@BenVoigt這是我聽到的第一個。你能提供一個參考嗎? – bolov

+0

請參閱http://stackoverflow.com/a/3716360/103167 –

1

很可能是因爲它會徹底破壞整個基於堆棧的調用約定,這些約定幾乎爲我們服務了幾十年......幾乎每一個CPU都假設。