2012-12-26 50 views
7

一個函數需要返回兩個值給調用者。什麼是最好的實施方式?返回std :: pair時會發生RVO嗎?

選項1:

pair<U,V> myfunc() 
{ 
... 
return make_pair(getU(),getV()); 
} 

pair<U,V> mypair = myfunc(); 

選項1.1:

// Same defn 
U u; V v; 
tie(u,v) = myfunc(); 

選項2:

void myfunc(U& u , V& v) 
{ 
u = getU(); v= getV(); 
} 

U u; V v; 
myfunc(u,v); 

我知道與選項2,有沒有拷貝/移動,但它看起來醜陋。 Option1,1.1中是否會出現複製/移動?讓我們假設U和V是支持複製/移動操作的巨大對象。

問:從理論上講,根據標準進行RVO/NRVO優化是否可行?如果是,是否已經實現了gcc或其他編譯器?

+1

我不知道的關於'的std :: pair'任何會抑制RVO/NRVO。通過包含一個可以告訴你何時發生副本的拷貝構造函數來測試通常相當容易。 –

+1

g ++實現了阻止複製對的RVO,但是您仍然擁有u和v的副本。 –

+0

我運行了一些測試,發現使用g ++,哪一個更快取決於內聯的可能性以及U和V的複製構造函數的複雜性。如果你只是在尋找性能,我想你會必須對其進行配置以確定哪個最快。 –

回答

8

返回時會出現RVO std::pair

是的,它可以。

保證會發生嗎?

不,它不是。


C++ 11標準:12.8節/ 31:

當滿足特定條件時,一種實現被允許省略類對象的複製/移動結構,即使該對象的複製/移動構造函數和/或析構函數具有副作用。

複製elision不是一個保證功能。這是一個優化編譯器可以執行只要他們可以。沒有什麼特別的w.r.t std::pair。如果編譯器足夠好以檢測優化機會,它將這樣做。所以你的問題是編譯器的具體問題,但是對於任何其他類,同樣的規則適用於std::pair

1

RVO或Copy elision依賴於編譯器,因此如果您想擁有RVO並避免調用Copy構造函數,最佳選擇是使用指針。

在我們的產品中,我們使用使用指針和boost容器指針來避免Copy構造函數。這的確提高了10%左右的性能。

回到你的問題, 在選項1中,U和V的拷貝構造函數不會被調用,因爲你沒有返回U或V,而是返回std :: pair對象,所以它的拷貝構造函數會被調用,大多數編譯器都會明確地使用RVO在這裏避免這種情況。

感謝 尼拉吉瑞斯

4

RVO雖然不能保證,在C++ 11的功能,你已經定義它,我認爲必須把收益起碼,所以我建議留下更清晰的定義,而而不是讓它接受輸出變量(除非你有具體的使用策略)。

此外,即使此示例確實使用了RVO,您明確使用make_pair意味着您將始終至少有一個額外的對構造,從而進行移動操作。更改它返回一個括號初始化表達式:

return { getU(), getV() }; 
相關問題