[英]How to ensure moving without impeding RVO?
當從函數返回一個對象時,自C ++ 11以來可能發生以下情況之一,假設定義了move-and-copy-constructors(另請參見本文末尾的示例):
對前3個案例的建議不是使用顯式的std::move
,因為無論如何都要執行移動並且可能阻止可能的RVO,例如參見此SO帖子 。
但是,在4.情況下,顯式的std::move
會提高性能。 但是,作為一個既不會閱讀標准也不會閱讀匯編程序的人,需要花費大量時間來區分案例1-3和案例4。
因此,我的問題是:是否有辦法以統一的方式處理所有上述案例,例如:
以下是一些示例,也可以用作測試用例。
所有示例都使用以下helper-class-definition:
struct A{
int x;
A(int x_);
A(const A& a);
A(A&& a);
~A();
};
1.例子: 1.case,RVO執行, 現場演示 , 結果匯編 :
A callee1(){
A a(0);
return a;
}
2.示例: 1.case,RVO執行, 實時演示 , 生成匯編程序 :
A callee2(bool which){
return which? A(0) : A(1);
}
3.示例: 2.case,符合copy-elision,RVO未執行, 實時演示 , 生成的匯編程序 :
A callee3(bool which){
A a(0);
A b(1);
if(which)
return a;
else
return b;
}
4.示例: 3.case,不符合copy-elision( x
是函數參數),但是對於移動, 實時演示 , 生成的匯編程序 :
A callee4(A x){
return x;
}
5.例子: 4.case,沒有copy-elision或者隱式移動(參見這篇SO帖子 ), live-demonstration , 結果匯編 :
A callee5(bool which){
A a(0);
A b(1);
return which ? a : b;
}
6.示例: 4.case,沒有copy-elision或隱式移動, live-demonstration , 得到的匯編程序 :
A callee6(){
std::pair<A,int> x{0,1};
return x.first;
}
如果滿足以下任何條件,編譯器(通常)無法執行RVO:
在情況1中,您應該使用std::move
或使用if
語句而不是使用三元運算符來編寫代碼。 在案例2中,您必須使用std::move
。 在案例3中,您還應該明確使用std::move
。
處理案例1.我們可以通過依賴if
語句來返回局部變量而不是三元運算符來確保移動的值:
A whichOne(bool which) {
A a(0);
A b(1);
if(which) {
return a;
} else {
return b;
}
}
如果您真的更喜歡使用三元運算符,請在兩個條件std::move
明確使用std::move
:
A whichOne(bool which) {
A a(0);
A b(1);
return which ? std::move(a) : std::move(b);
}
如果我只想移動a
而不是b
怎么辦? 我們可以通過在條件中顯式構造它來處理這種情況。 在這種情況下,保證構造的值經歷RVO,因為三元的兩側產生prvalue 。
A whichOne(bool which) {
A a(0);
A b(1);
return which
? A(std::move(a)) // prvalue move-constructed from a
: A(b); // prvalue copy-constructed from b
}
處理案例2和3.這非常簡單:在返回對象的成員時,或者在返回來自數組或指針的引用時使用std::move
。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.