2017-08-07 67 views
4

例如:可以std :: move()或它的顯式等價於本地變量allow elision?

Big create() 
{ 
    Big x; 
    return std::move(x); 
// return static_cast<typename std::remove_reference<T>::type&&>(t) // why not elide here? 
} 

假設應用std::move()返回一個局部變量抑制移動的語義,因爲編譯器不能做出的一般功能的內部工作,有關情況下,當這些假設是什麼做任何假設沒有必要的,例如當:

  1. std::move(x)內聯(可能永遠)
  2. std::move(x)寫爲:static_cast<typename std::remove_reference<T>::type&&>(t)

根據目前的標準,實現允許應用NRVO ...

- return語句中與類返回類型,一種功能,當 表達的名稱將與 (忽略cv-qualification)相同類型的非易失性自動對象( 函數參數或由 異常聲明處理程序(18.3)引入的變量)作爲函數返回類型,副本/移動 操作可以通過構造auto來省略matic對象直接撥入函數調用的返回對象

顯然,1)和2)都不具備資格。除了使用std::move()返回本地變量的事實是多餘的,爲什麼是必要的限制

+3

類似std :: move()的轉換是在編譯時執行的,所以elision是沒有意義的;它們只是編譯器改變如何看待類型的指示。 –

+3

[在返回的對象上使用'std :: move()'是多餘的。](https://stackoverflow.com/a/14856553/501250) – cdhowie

+1

「假設本地變量上的std :: move()移動語義等因素等「 - 聽起來不對。 – einpoklum

回答

2

重新閱讀這個問題後,我對它有不同的理解。我把這個問題看作爲'爲什麼std::move()抑制(N)RVO'

問題中提供的標準引用有錯誤的亮點。它應該是

在與類返回類型的功能,當 表達式是一個非易失性自動對象(除了 函數參數或由 引入一個可變的其它名稱的返回語句

處理程序的異常聲明(18.3))與同類型 (忽略CV-資質)作爲函數的返回類型

什麼抑制NRVO這裏不是std::move()被調用,但事實上,回報值爲std::move不是X,而是X&&。它與不匹配的功能簽名!

+0

雖然這是很好的建議,但我不認爲它實際上回答這個問題。 –

+0

@NirFriedman,我相信它的確如此,通過模仿(這是一個詞?)整個問題。 – SergeyA

+1

我的意思是,因爲一個問題的答案是沒有必要寫出最好的C++,並不意味着問題是無效的。 「不要做X」並不是對「爲什麼X不以這種方式工作」的回答,特別是當作者已經意識到這一點非常明確時。就目前而言,這個答案中的大部分信息已經存在於問題中。 –

2

您應該清楚確切地說明「allow elision」的含義。首先,根據「as-if」規則,編譯器可以做任何想做的事情。也就是說,只要該程序集的行爲正確,編譯器就可以吐出所需的任何程序集。這意味着編譯器可以隱藏它想要的任何構造函數,但它必須證明程序的行爲是否相同,而不管構造函數是否被調用。

那麼爲什麼elision的特殊規則?那麼,這些情況下編譯器可以省略構造函數調用(因此也是析構函數調用)沒有證明行爲是相同的。這是非常有用的,因爲有許多類型的構造函數非常不平凡(比如說,string),並且編譯器實際上通常不能證明他們可以安全地退出(在合理的時間範圍內) (過去,優化堆分配是否合法,因爲它基本上是一個全局變量的變異),甚至缺乏清晰度。

因此,我們希望有出於性能方面的考慮。然而,就行爲而言,它基本上是在標準中指定一個特例。特例越大,我們向標準介紹的複雜性就越高。因此,我們的目標應該是使得允許的範圍足夠廣泛,涵蓋我們關心的有用案例,但沒有更廣泛的範圍。

你正在接近這個:爲什麼不把這個特殊情況做得像實用一樣大?實際上,情況恰恰相反。爲了擴大elision的允許範圍,需要證明它非常有價值。

相關問題