2013-04-03 69 views
4

我不知道當我有這樣的功能,會發生什麼C++ 11會發生什麼?當函數返回

'temp'在被銷燬之前被拷貝到一個臨時的r值(超出範圍)並且C++ 11可能被NRVO優化(所以'temp'的拷貝被直接寫入返回目的地插槽)?

+4

複製最有可能通過C++ 03 *和* C++ 11中的NRVO消除。 – juanchopanza

+1

它可能是:a)如果移動ctor可用,則移動;或b)如果第一個不起作用,則複製。當然,(N)RVO可以同時應用兩次。 – Xeo

+1

既然你不需要'b'的副本,第二個參數應該改成'const stringmap&b'。對於第一個,我建議將它移動到'temp',即'stringmap temp(std :: move(a));'。這不會破壞NRVO,所以返回值仍然是最優化的。 –

回答

7

什麼都應該被複制。有兩種可能性:

  • temp被移動到調用者範圍內的對象;或者
  • 移動被取消,temp成爲調用者範圍中對象的別名。這被稱爲「返回值優化」。

在2011年之前(具體而言,沒有移動語義),第一種情況需要複製而不是移動。第二種情況允許在C++ 98和11中使用。

+0

在'std :: unordered_map 的情況下是這樣,沒有任何東西被複制,但是如果返回類型不可移動,通常可以有一個副本。 – bames53

4

這通常會在沒有任何特殊規則的情況下從temp複製到函數的返回值。但是,標準中有兩條規則旨在改善這一點。第一個是,該拷貝可以被省略(12.8/31):比

在與類返回類型的函數返回語句,當表達是一種非揮發性的自動對象的名稱

(其他一個功能或catch子句參數)用相同cvunqualified類型作爲函數返回類型時,複製/移動操作可以通過直接構建自動物體插入函數的返回值

這通常稱爲命名被省略返回值優化(NRVO),return value optimization (RVO)的特例。

第二個問題是,由於這種情況下滿足複製省略上述標準,它將首先被認爲是移動(12.8/32):

當的複製操作的省音的標準是滿足或將被滿足,除了源對象是函數參數,並且要被複制的對象由左值指定的情況下,首先執行用於選擇副本的構造函數的重載解析,就好像該對象由右值。

因此,編譯器將嘗試以下步驟:

  • 是否階層有一個移動構造函數?
    • 如果是這樣,請移動它或不要移動。
    • 如果沒有,該類是否有複製構造函數?
      • 如果是這樣,請移動它或刪除副本。
      • 如果不是,我們不能複製或移動此對象。

注意的是,類必須有一張移動或拷貝構造函數這個工作,即使移動或複製會被省略。

5

NRVO意味着temp本身是在返回值位置構造的。沒有RVO,是的,temp被複制/從堆棧中的位置移動到被銷燬之前的返回值位置。

+1

在沒有RVO的C++ 11中,它應該被移動,而不是被複制。 –