2012-10-02 33 views
0

我來自Java哪裏有什麼是引用,所以我想弄清楚C++實例創建的基本。返回本地是否也涉及創建返回臨時?

Employee getEmp(int a) { 
    Employee local(a); 
    return local; 
} 
Employee myEmp = m.getEmp(10); 

是否有3次員工實例化(無RVO)是否正確?
1 - 創建一個本地副本
2 - 臨時被結合參考創建)
3 - 爲什麼有必要在步驟2中創建myEmp

?爲什麼不直接複製本地到myEmp?

如果我打算只使用Ubuntu,那麼我應該依靠RVO嗎?我是否正確地使用RVO來完成兩個實例創建(在第二步中不需要)?

謝謝!!!

回答

2

函數返回的語義是獨立於 對返回值做的事情定義的:返回值被複制到某處,其中 在本地堆棧框架被破壞時它不會消失。因此,沒有 視網膜靜脈阻塞,在你的榜樣,您有:

一個局部變量,名爲 local
  1. 建設,在棧幀的getEmp

  2. 將調用者 能夠訪問的返回對象的構造複製到某處。通常,調用方爲其自己的堆棧幀中的返回對象分配內存,並將帶有該內存地址的隱藏參數 傳遞給被調用的函數。 RVO或NRVO 允許編譯器將此返回的對象「別名」爲本地對象:在 您的情況下,在地址中創建變量local作爲 傳入的隱藏參數,而不是本地堆棧幀。

  3. 返回後,返回的對象將被「使用」,然後在 處破壞完整表達式的結尾。 如果這個用法是使用複製構造函數初始化一個本地的 變量,則中間值可以是 ;編譯器將傳遞實際對象的地址爲 構造爲被調用函數的隱藏參數。 (嚴格來說 來講,這不是NRVO,但它是相關的。)其他用途,但是, 不能被忽略;如果返回的值用於對現有變量的分配,例如,賦值運算符將需要對實例進行分配的 引用。 中間對象的形式要求在那裏,因爲大多數返回值的使用是 而不是作爲拷貝構造函數的參數。

最後,鑑於現代編譯器技術,你也許可以指望 編譯系統eliding上面的第二個副本。第一個副本 (RVO或NRVO)可能會更難一些。我希望看到它 系統在簡單情況下,像上面:RVO隨時有一個臨時的 單一的回報,NRVO隨時有一個返回 返回在 功能的最外層範圍內定義的命名變量。 NRVO(實際上也是RVO,儘管我不知道爲什麼),如果函數中有多個回報,則不太可能發生這種情況。

+0

既然我們有RVO和copy elision,那麼在const&技巧中有任何需要。我的意思是使用 - Employee const&myEmp = m.getEmp(10);如果我理解正確,就沒有必要了,因爲RVO和copy elision會保存副本。 –

+0

用'const&'聲明一個局部變量,並用一個返回值的函數對它進行初始化,它具有與用值類型聲明局部變量完全相同的語義。並始終有。這裏沒有什麼改變;使用帶引用類型的局部變量從來沒有意義_unless_它是由返回引用的函數初始化的。 –

+0

用const聲明局部變量並擴展臨時對象的生存期,因此不需要額外的副本 –

3

沒有RVO/NRVOcopy elision存在的Employee(int)一個呼叫和copy c-tor兩個電話,一個當回報,一個構建myEmp時。與RVOcopy elision - 一個電話Employee(int)和可能零呼叫複製c-tor。

由於您想從另一個對象構建新對象(工作到copy c-tor),因此不需要copy elision的複製構造函數的第二次調用是強制性的。

+0

完全如我所料。你能解釋爲什麼沒有RVO的第2步需要嗎?爲什麼dosnt直接將它複製到分配?另外,依靠RVO是否「安全」? 您評論 - 「或者mb沒有電話複製c-tor,如果myEmp不會使用」沒有清除給我。你的意思是說,如果myEmp沒有做任何事情比不做複製?如果這是你的意思而不是明確的。 –

+0

@ user1495181編輯。 – ForEveR