2009-07-28 45 views
7

我有它返回Foo類型的對象的函數:分配的功能,因此,它返回一個Foo一個const美孚&

Foo getFoo(); 

我知道下面將編譯工作,但我爲什麼會曾經做過嗎?

const Foo& myFoo = getFoo(); 

對我來說,下面是更可讀,並且不強迫我記得C++允許我的r值賦值給一個const引用:

const Foo myFoo = getFoo(); 

什麼兩者之間的差異?爲什麼我會使用第一個?爲什麼我會在第一次使用第二個?

回答

4

流行的觀點相反,也不能保證分配的值返回一個對象const引用的函數的結果將導致更少的複印速度比它分配給了對象本身。

當您將一個右值賦給一個const引用時,編譯器可以用兩種方式之一來綁定該引用。它可以通過複製右值並將引用綁定到該值來創建新的臨時值,或者可以將引用直接綁定到右值。

如果編譯器無法進行'顯而易見'的優化來刪除臨時文件,並且爲返回值getFoo刪除拷貝構造函數,那麼它有多大可能做到更高效的綁定形式右值爲const引用而不創建新的臨時值?

使用const引用的一個原因是使該函數對潛在的切片更健壯。如果返回類型實際上是從Foo派生的類型,那麼即使編譯器確實從函數返回的右值創建臨時對象,也將保證不分片。編譯器也會對派生類析構函數生成正確的調用,而不管基類中的析構函數是否爲虛擬的。這是因爲創建的臨時對象的類型是基於正在分配的表達式的類型,而不是基於正在初始化的引用的類型。

注意,返回值的多少份的問題是由從返回值優化完全獨立和命名返回值優化。這些優化指的是消除評估返回表達式或命名局部變量的右值結果副本到函數本身的函數的返回值中。顯然,在最好的情況下,可以進行返回值優化,並且可以消除返回值的臨時值,從而不會在返回的對象上執行副本。

1

它是有效的,以允許這種圖案的:

void foo(const SomeType &); 

foo(SomeType(bar)) 

在這種情況下,臨時SOMETYPE被構造並傳遞到foo。最有可能的是,您也可以在堆棧上臨時引用常量,這是用於在標準中定義此行爲的措辭的副作用。請注意,如評論中提到的那樣,臨時的生命週期延長到參考本身的壽命。

+0

所以沒有很好的理由去做`const Foo&myFoo = getFoo()`? – 2009-07-28 21:04:03

+0

這個嘗試ot回答有什麼問題嗎? – 2009-07-28 21:46:35

+0

「你也可以參考臨時工比他們自己活得更久」。不是這樣,你不能。在問題的第二行代碼中,直到`myFoo`超出範圍,從getFoo()返回的臨時數據才被銷燬。 http://herbsutter.wordpress.com/2008/01/01/gotw-88-a-candidate-for-the-most-important-const/ – 2009-07-28 22:29:43

0

這可能有幾個原因:

如果你不想const對象簡稱? 例如,這將不起作用:

 
    const Foo &myFoo = getFoo(); 
    myFoo.myfield = x; 

或者,如果你是從的getFoo返回一個臨時對象()?這將警告有關返回引用(或地址)到本地:

 
    const Foo &getFoo(void) 
    { 
     Foo localFoo(); 
     // do the things you want to localFoo 
     return(localFoo); 
    } 

const Foo& myFoo = getFoo()的內部做幾乎同樣的事情 Foo myFoo = getFoo()這樣的說法有性能值的常量裁判回報是無效的。我發現返回合理大小的物體沒有任何問題。

免責聲明 - 我沒有在gcc上試過這些例子。您的里程可能會有所不同。

+0

你不能在`myFoo上做非常量的事情`適用於將`getFoo()`的返回值存儲在`const Foo&`或`const Foo`中。另外,我特別提到`getFoo()`返回`const Foo`而不是`const Foo&`。 – 2009-07-28 21:25:54

4

我覺得GotW #88回答了這個最好的