2014-05-15 59 views
14

曾幾何時,我假定這樣的代碼會失敗:Do * non * -const引用延長了臨時對象的生命嗎?

const MyClass& obj = MyClass(); 
obj.DoSomething(); 

因爲MyClass的對象將在其全表達的端部被破壞,留下OBJ作爲懸空參考。但是,我在這裏瞭解到這不是真的;該標準實際上有一個特殊的規定,允許const引用使臨時對象保持活動狀態,直到所有引用被自己銷燬。但是,有人強調,只有const引用纔有這種力量。今天,我將VS2012中的代碼作爲實驗運行。

struct Foo 
{ 
    Foo() { std::cout << "ctor" << std::endl; } 
    ~Foo() { std::cout << "dtor" << std::endl; } 
}; 

void f() 
{ 
    Foo& f = Foo(); 
    std::cout << "Hello world" << std::endl; 
} 

輸出調用f()當是:

ctor 
Hello world 
dtor 

所以我不得不看看C++ 11標準草案,只發現這個(第12.2/4):

存在兩種情況,其中臨時數在 不同於完整表達式末尾的點處被銷燬。第一個上下文[不適用 ]。第二個上下文是當一個引用綁定到一個 臨時。引用所綁定到的臨時引用或引用綁定到的子對象的完整對象的臨時引用臨時引用的生存期保持不變。

上面顯然沒有字const。所以;有這種行爲已被改變爲C + + 11,我是否錯開const事情開始,或VS2012有一個錯誤,我只是沒有找到相關部分的標準?

回答

13

行爲並沒有改變,你只需要把你的警告等級提高到/W4。 VisualStudio甚至對非const左值引用作爲編譯器擴展實現了生命週期擴展規則。在這種情況下,將右值綁定到非const引用的行爲與您將其綁定到const引用的行爲相同。

隨着/W4你會看到這一點:

warning C4239: nonstandard extension used : 'initializing' : conversion from 'Foo' to 'Foo &' 
1> A non-const reference may only be bound to an lvalue 

不允許右值的結合非const左值參考的文本可以在§8.5.3/ 5

找到

—否則,該參考文獻應爲對非易失性const類型的左值參考(即,cv1應爲 const),或者引用應該是右值引用。
[實施例:

double& rd2 = 2.0; // error: not an lvalue and reference not const 
    int i = 2; 
    double& rd3 = i; // error: type mismatch and reference not const 

末端示例]

引用的聲明的後半部分是允許一個臨時的對一個rvalue參照結合,如圖litb's answer

string &&s = string("hello"); 

這與在§12.2/ 5的壽命延長規則相結合,是指臨時的壽命現在將在(右值)的壽命相匹配引用它被綁定到。

+2

,你允許右值綁定到一個非const的事實左值參考本身就是一個擴展。 – Brian

+2

@Brian是不是我說的? – Praetorian

+0

@Praetorian我的確如此。所以「只有const引用延長生命期」規則是其他規則的副作用,說明只有const引用可以綁定到rvalues? – dlf

4

沒有,因爲右值引用不需要是const,所以標準報價是正確的

string &&s = string("hello"); 

壽命仍然enlargened。使非代碼爲非const的左值引用的約束條件是在第8節(請注意,它不是在引用的段落中添加「const」和「右值引用」等的正確位置,您需要一個主動拒絕的這樣的綁定,而不僅僅是說這樣的綁定的生命週期沒有擴大,因爲你會保持綁定本身仍然良好)。

+0

這個問題真的要求*三個*是 - 沒有問題鏈接在一起。我不清楚哪一個你回答*不*。或者你對所有三個人都給出同樣的答案嗎? –

11

本節中從未出現const這個詞。規則 一直以來(從我記得的時間起) 用於初始化引用的臨時文件的生存期延長到 以匹配引用的值,而不管引用的類型爲 。

有時在20世紀80年代後期(非常標準),C++引入了 規則,即暫時不能用於初始化非const引用的 。用 臨時初始化一個非const引用仍然會延長生命週期(推測是),但是 ,因爲你不能這麼做......大多數編譯器實現了 一個過渡期,其中這樣的初始化只會發出一個警告( ) (並延長了使用期限)。

出於某些原因,當微軟終於決定實施 C++(一段時間在1990年代初),他們決定不 實施新規則,並 用臨時非const引用允許初始化(不甚至出現警告,當時大多數其他供應商正逐漸將 警告轉化爲錯誤)。當然,實施了通常的生命週期規則。

最後,在C++ 11中,引入了新類型的引用 ,它們允許(甚至是需要)初始化,並且臨時爲 。但是,關於臨時人員的生命週期的規則並沒有被更改,但是: ;用於初始化 參考(不管參考類型如何)的臨時文件的生命週期延長了 。

(除了少數例外:我不建議使用臨時 初始化在初始化 列表類成員參考。)

+0

你能否詳細說明最後一段關於成員引用的問題?無論如何,我從來沒有想過要這樣做,但我會對你的確切推理感興趣。 –

+2

@ChristianHackl用於初始化成員引用的臨時的生命週期不擴展到引用的生命週期;它的生命期結束於構造函數的末尾(這會導致懸而未決的引用)。 –

+0

感謝您的澄清。我會直覺地猜到,但確認後很高興。仍然讓我想知道爲什麼這樣的事情首先不需要編譯器診斷。 –

相關問題